3)Servlet 过滤器

  Spring Security 过滤器链是一个非常复杂且灵活的引擎。Spring Security 的 Servlet 支持基于 Servlet 过滤器,因此通常首先了解过滤器的作用会很有帮助。 下图显示了单个 HTTP 请求的处理程序的典型分层。

  客户端向应用程序发送请求,然后容器创建一个 FilterChain ,其中包含应根据请求URI的路径处理 HttpServletRequest 的过滤器和 Servlet。 在 Spring MVC 应用程序中,Servlet 是 DispatcherServlet 的实例。 一个 Servlet 最多只能处理一个 HttpServletRequest 和 HttpServletResponse 。 但是,可以使用多个过滤器来处理,比如:

  • 阻止下游过滤器或 Servlet 被调用。 在这种情况下,过滤器通常用来写 HttpServletResponse

  • 使用下游过滤器和 Servlet 来修改 HttpServletRequest或 HttpServletResponse

   FilterChain 中 Filter s之间通过传递来发挥过滤器的作用。

   Filter的用法例子:

1 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
2 // do something before the rest of the application
3 chain.doFilter(request, response); // invoke the rest of the application
4 // do something after the rest of the application
5 }

  注意,由于过滤器仅影响下游过滤器和 Servlet,因此调用每个过滤器的顺序非常重要

  下面来认识 Spring Security 中的几种类型的 Filter。

  DelegatingFilterProxy

  Spring 框架提供了一个名为 DelegatingFilterProxy 的 Filter 实现,该实现允许在 Servlet 容器的生命周期和 Spring 的 ApplicationContext 之间进行桥接。 顾名思义,它是一个代理过滤器,它充当过滤器,但它并未执行实际工作,而是将过滤委托给其他人。Servlet 容器允许符合自己的标准的  Filters 注册,但自己不了解 Spring 定义的 Bean, DelegatingFilterProxy 可以通过标准的 Servlet 容器机制来被注册,但是它将所有工作委托给实现了 Filter 的 Spring Bean。

  以下是在 Spring Security 中添加 DelegatingFilterProxy 的方式,位置: AbstractSecurityWebApplicationInitializer#insertSpringSecurityFilterChain()

 1     /**
2 * Registers the springSecurityFilterChain
3 * @param servletContext the {@link ServletContext}
4 */
5 private void insertSpringSecurityFilterChain(ServletContext servletContext) {
6 String filterName = DEFAULT_FILTER_NAME;// This is a spring name which is called "springSecurityFilterChain"
7 DelegatingFilterProxy springSecurityFilterChain = new DelegatingFilterProxy(
8 filterName);
9 String contextAttribute = getWebApplicationContextAttribute();
10 if (contextAttribute != null) {
11 springSecurityFilterChain.setContextAttribute(contextAttribute);
12 }
13 registerFilter(servletContext, true, filterName, springSecurityFilterChain);
14 }

  名为 springSecurityFilterChain 的 Bean 的创建,位置:WebSecurityConfiguration#springSecurityFilterChain()

 1     /**
2 * Creates the Spring Security Filter Chain
3 * @return the {@link Filter} that represents the security filter chain
4 * @throws Exception
5 */
6 @Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
7 public Filter springSecurityFilterChain() throws Exception {
8 boolean hasConfigurers = webSecurityConfigurers != null
9 && !webSecurityConfigurers.isEmpty();
10 if (!hasConfigurers) {
11 WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
12 .postProcess(new WebSecurityConfigurerAdapter() {
13 });
14 webSecurity.apply(adapter);
15 }
16 return webSecurity.build();
17 }

  下面是 DelegatingFilterProxy 如何传递  Filters 和  FilterChain 的图。

   DelegatingFilterProxy 从 ApplicationContext 查找 Bean Filter0 ,然后调用 Bean Filter0 。  DelegatingFilterProxy 的伪代码:

1 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
2 // Lazily get Filter that was registered as a Spring Bean
3 // For the example in DelegatingFilterProxy delegate is an instance of Bean Filter0
4 Filter delegate = getFilterBean(someBeanName);
5 // delegate work to the Spring Bean
6 delegate.doFilter(request, response);
7 }

  一旦 Servlet 请求到达过滤器,DelegatingFilterProxy 就会被初始化,作为其初始化的一部分,它会寻找过滤器名称,在上面的示例中,过滤器名称为 springSecurityFilterChain 。

  DelegatingFilterProxy 的另一个好处是,它允许延迟查找 Filter bean 实例。 这很重要,因为容器需要在容器启动之前注册 Filter 实例。 但是,Spring 通常使用 ContextLoaderListener来加载 Spring Bean,但需要等到注册完 Filter 实例之后,Spring 才会完成加载这一操作。

  ContextLoaderListener是引导侦听器。它启动和关闭 Spring 的 Root WebApplicationContext。

  ContextLoaderListener是可选的,你可以仅配置 Dispatcher Servlet 来运行 Spring 应用程序,但是对于 Spring Security,则需要一个。

  DispatcherServlet的上下文专用于与 MVC 相关的 Bean,例如控制器,视图,处理程序。它不包括与安全性相关的 bean,要使用 Spring Security,必须将与安全性相关的 bean 放在Root WebApplicationContext 中,因此需要配置  ContextLoaderListener。

FilterChainProxy

  Spring Security 的 Servlet 支持包含在 FilterChainProxy 中。  FilterChainProxy是 Spring Security 提供的一个特殊过滤器,允许通过SecurityFilterChain委派许多过滤器实例。 由于FilterChainProxy是 Bean,因此通常将其包装在 DelegatingFilterProxy 中。

SecurityFilterChain

   FilterChainProxy 使用 SecurityFilterChain 确定应对此请求调用哪些 Spring Security 过滤器。

   SecurityFilterChain中的安全过滤器通常是 Bean,但它们是使用 FilterChainProxy 而不是 DelegatingFilterProxy 来注册的。  FilterChainProxy 具有直接向 Servlet 容器或 DelegatingFilterProxy 注册的许多优点。 首先,它为 Spring Security 的所有 Servlet 支持提供了一个起点。 因此,如果您想对Spring Security的 Servlet 支持进行故障排除,那么在 FilterChainProxy 中添加调试点是一个很好的起点。

  其次,由于 FilterChainProxy 对于 Spring Security 的使用至关重要,因此它可以执行不被视为可选的任务。 例如,它清除 SecurityContext 以避免内存泄漏。 它还使用 Spring Security 的 HttpFirewall 来保护应用程序免受某些类型的攻击。

  此外,它在确定何时应调用 SecurityFilterChain 时提供了更大的灵活性。 在Servlet容器中,仅根据URL调用过滤器。 但是, FilterChainProxy 可以利用 RequestMatcher 接口,根据 HttpServletRequest 中的任何内容确定调用。

  实际上, FilterChainProxy 可用于确定应使用哪个 SecurityFilterChain 。 如果你的应用程序在各种不同的方面提供了相对独立的配置。

查看springSecurityFilterChain的方法

  通过注解获取已注册的 springSecurityFilterChain 的方法

1 @Autowired
2 @Qualifier("springSecurityFilterChain")
3 private Filter springSecurityFilterChain;

  在这里,使用名称为 springSecurityFilterChain 的  @Qualifier ,其类型为 Filter 而不是  FilterChainProxy 。这是因为在 WebSecurityConfiguration 中的方法 springSecurityFilterChain() ,它创建 Spring Security 的过滤器链,返回类型 Filter  ,而不是 FilterChainProxy 。

  接下来需要将此对象转换为 FilterChainProxy 并调用 getFilterChains() 方法:

1 public void getFilters() {
2 FilterChainProxy filterChainProxy = (FilterChainProxy) springSecurityFilterChain;
3 List<SecurityFilterChain> list = filterChainProxy.getFilterChains();
4 list.stream()
5   .flatMap(chain -> chain.getFilters().stream())
6   .forEach(filter -> System.out.println(filter.getClass()));
7 }

  在自己的 WebSecurityConfig (Spring Security)中启用安全性调试,该调试将记录每个请求的详细安全性信息。我们可以使用 debug 属性启用安全调试:

1 @EnableWebSecurity(debug = true)

  这样,当我们向服务器发送请求时,所有请求信息都会被记录下来。我们还将能够看到整个默认的 Spring Security 过滤器链:

 1 Security filter chain: [
2 WebAsyncManagerIntegrationFilter
3 SecurityContextPersistenceFilter
4 HeaderWriterFilter
5 CsrfFilter
6 LogoutFilter
7 UsernamePasswordAuthenticationFilter
8 DefaultLoginPageGeneratingFilter
9 DefaultLogoutPageGeneratingFilter
10 RequestCacheAwareFilter
11 SecurityContextHolderAwareRequestFilter
12 AnonymousAuthenticationFilter
13 SessionManagementFilter
14
15 ExceptionTranslationFilter
16 VBFilterSecurityInterceptor
17 FilterSecurityInterceptor
18 ]

  最后,让我们看一些重要的安全过滤器:

  • SecurityContextPersistenceFilter :从 JSESSIONID 恢复身份验证

  • UsernamePasswordAuthenticationFilter :执行身份验证,默认情况下响应“ /login” URL

  • AnonymousAuthenticationFilter :当 SecurityContextHolder 中没有身份验证对象时,它将创建一个匿名身份验证对象并将其放置在此处

  • FilterSecurityInterceptor :拒绝访问时引发异常,可能会抛出身份验证和授权异常

  • ExceptionTranslationFilter :从 FilterSecurityInterceptor 捕获安全异常

  其中 VBFilterSecurityInterceptor 是自定义的验证过滤器,继承了 AbstractSecurityInterceptor 并实现了 javax.servlet.Filter 接口,可以在你的 Spring Security 配置 Bean中的 configure() 方法中通过 http.addFilterBefore(Filter filter, Class<? extends Filter> beforeFilter) 来配置:

1     @Override
2 protected void configure(HttpSecurity http) throws Exception {
3 http.addFilterBefore(vbFilterSecurityInterceptor, FilterSecurityInterceptor.class);
4 }

参考:Spring Security 官方文档,DelegatingFilterProxy ,springSecurityFilterChain ,ContextLoaderListener and FilterChainProxyHow Spring Security Filter Chain worksOverview and Need for DelegatingFilterProxy in Spring

Spring Security:Servlet 过滤器(三)的更多相关文章

  1. Spring Security入门(1-12)Spring Security 的过滤器机制

    Servlet过滤器被用来拦截用户请求来进行请求之前或之后的处理,或者干脆重定向这个请求,这取决于servlet过滤器的功能. Servlet过滤器处理之后的目标servlet是 MVC 分发web ...

  2. spring security 图解过滤器的使用

    1. HttpSessionContextIntegrationFilter 位于过滤器顶端,第一个起作用的过滤器. 用途一,在执行其他过滤器之前,率先判断用户的session中是否已经存在一个Sec ...

  3. Re:从零开始的Spring Security Oauth2(三)

    上一篇文章中我们介绍了获取token的流程,这一篇重点分析一下,携带token访问受限资源时,内部的工作流程. @EnableResourceServer与@EnableAuthorizationSe ...

  4. Spring Security认证配置(三)

    学习本章之前,可以先了解下上篇Spring Security认证配置(二) 本篇想要达到这样几个目的: 1.登录成功处理 2.登录失败处理 3.调用方自定义登录后处理类型 具体配置代码如下: spri ...

  5. spring security基本知识(三) 过滤详细说明

    在我们前面的文章Spring Security 初识(一)中,我们看到了一个最简单的 Spring Security 配置,会要求所有的请求都要经过认证.但是,这并不是我们想要的,我们通常想自定义应用 ...

  6. spring-security-4 (3)spring security过滤器的创建与注册原理

    spring security是通过一个过滤器链来保护你的web应用安全.在spring security中,该过滤链的名称为springSecurityFilterChain,类型为FilterCh ...

  7. Spring Security(2):过滤器链(filter chain)的介绍

    上一节中,主要讲了Spring Security认证和授权的核心组件及核心方法.但是,什么时候调用这些方法呢?答案就是Filter和AOP.Spring Security在我们进行用户认证以及授予权限 ...

  8. Spring Security(三十一):9.6 Localization(本地化)

    Spring Security supports localization of exception messages that end users are likely to see. If you ...

  9. Spring Security(四) —— 核心过滤器源码分析

    摘要: 原创出处 https://www.cnkirito.moe/spring-security-4/ 「老徐」欢迎转载,保留摘要,谢谢! 4 过滤器详解 前面的部分,我们关注了Spring Sec ...

随机推荐

  1. Java定时任务Quartz

    第一步:pom文件中添加依赖包 第二步:创建xml文件,名称为:spring-scheduler 路径如下图: 第三步:spring-scheduler配置详情 <!--创建任务--> & ...

  2. PHP操作用户提交内容时需要注意的危险函数

    对于我们的程序开发来说,用户的输入是解决安全性问题的第一大入口.为什么这么说呢?不管是SQL注入.XSS还是文件上传漏洞,全部都和用户提交的输入参数有关.今天我们不讲这些问题,我们主要探讨下面对用户的 ...

  3. lightweight openpose 入门实操笔记(pytorch环境)

    最近有个小项目要搞姿态识别,简单调研了一下2D的识别: 基本上是下面几种 (单人)single person 直接关键点回归 heatmap,感觉其实就是把一个点的标签弄成一个高斯分布 (多人)mul ...

  4. CI框架 core

    https://blog.csdn.net/admin_admin/article/details/51769805 1.扩展控制器 1.在application/core新建一个自己的控制器(MY_ ...

  5. xadmin使用富文本

    环境:pycharm django1.11.20 python2.7 后台xadmin(根据网络各种资料实现) 本教程接上篇如何安装 xadmin,如何不清楚,请看上一篇(django安装xadmin ...

  6. 鸿蒙内核源码分析(消息队列篇) | 进程间如何异步传递大数据 | 百篇博客分析OpenHarmony源码 | v33.02

    百篇博客系列篇.本篇为: v33.xx 鸿蒙内核源码分析(消息队列篇) | 进程间如何异步传递大数据 | 51.c.h .o 进程通讯相关篇为: v26.xx 鸿蒙内核源码分析(自旋锁篇) | 自旋锁 ...

  7. P1791-[国家集训队]人员雇佣【最大权闭合图】

    正题 题目链接:https://www.luogu.com.cn/problem/P1791 题目大意 有\(n\)个人,雇佣第\(i\)个需要\(A_i\)的费用,对于\(E_{i,j}\)表示如果 ...

  8. YbtOJ#631-次短路径【左偏树,最短路】

    正题 题目链接:https://www.ybtoj.com.cn/contest/114/problem/1 题目大意 给出\(n\)个点\(m\)条边的一张无向图,对于每个点\(i\)求不经过\(i ...

  9. 关于Servlet

    Servlet与CGI CGI(Common Gateway Interface),早期的Web服务器技术.执行模式:将服务端的资源基于进程运行. Servlet:运行模式改为单进程多线程的形式,利用 ...

  10. JVM学习笔记——堆

    堆 Heap 一个 JVM 只有一个堆,堆也是 Java 内存管理的核心区域.在 JVM 启动时堆被创建,同时大小在启动时已设定好,堆是 JVM 管理最大的一块内存空间,其大小可以调节. 堆的内存空间 ...