SpringSecurity里的filer们

这段文字主要源于对 https://docs.spring.io/spring-security/reference/servlet/architecture.html 的学习和理解,其实就是对下图的理解。
SecurityFilterChain
上图表达了下面几个类之间的关系:
DelegatingFilterProxy, FilterChainProxy (springSecurityFilterChain), SecurityFilterChain (security filter)
通过调用 SecurityFilterChain API 把 Security Filters 组装成一个或多个 chain,再设置给 FilterChainProxy 使用。

对于下图这样 FilterChainProxy 有多个 SecurityFilterChain 的情况,只会触发第一个匹配的 securityFilterChain。
Multiple SecurityFilterChain

1)使用 Spring Security

要使用 Spring Security,如果是在 Spring Boot 环境那么只需要导入 security 的 starter,Spring Boot 就会自动做下面的事。
Creates a servlet Filter as a bean named springSecurityFilterChain. This bean is responsible for all the security (protecting the application URLs, validating submitted username and passwords, redirecting to the log in form, and so on) within your application.
Registers the Filter with a bean named springSecurityFilterChain with the Servlet container for every request.
Creates a UserDetailsService bean with a username of user and a randomly generated password that is logged to the console.

不使用 Spring Boot 的情况下,就需要自己在 web.xml 文件中定义 springSecurityFilterChain。

<filter>
  <filter-name>springSecurityFilterChain</filter-name>
  <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
  <filter-name>springSecurityFilterChain</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

2)入口 DelegatingFilterProxy

下面通过源码简单看下 DelegatingFilterProxy 实例化的过程。
Tomcat 启动时会在 web 容器中初始化 DelegatingFilterProxy 实例,

DelegatingFilterProxy 本身既是一个 Filter 也是一个 ServletContextAware 的实例。 Spring 使用 ContextLoaderListener 来加载 spring 的 bean。org.springframework.web.context.support.GenericWebApplicationContext 则是 servlet context 和 spring context 真正交汇的地方。
从下面 DelegatingFilterProxy 实现的接口就可以感知到 DelegatingFilterProxy 最关键的作用就是作为Servlet Container 和 Spring Context 的桥梁
因为 Spring 要等 web context 初始化完成才能初始化自己的 context,所以在 spring 中定义的 filter beans 就要延迟初始化才行。通过延迟初始化就解决了 Filter 必须定义在 Servlet Container 中的问题。 Spring 很巧妙的通过 FilterChain 接口把这些 filter beans 串在一起

public class DelegatingFilterProxy extends GenericFilterBean

而 ServletContextAware 是 Spring 的一个接口。

public abstract class GenericFilterBean implements Filter, BeanNameAware, EnvironmentAware,
    EnvironmentCapable, ServletContextAware, InitializingBean, DisposableBean

从 DelegatingFilterProxy 的两个关键 fields:WebApplicationContext webApplicationContext 和 Filter delegate,也能知道 DelegatingFilterProxy 桥梁作用。

上图中的 delegate 是 FilterChainProxy 的实例。

3) FilterChainProxy 包装了 filers。

下图中 filterChian 包含的 filters 是不做任何特殊配置时的 16 个 filters。FilerChainProxy 就是通过调用它拥有的 filters 起到了对 request 做 filter 处理的作用,这就是称它为代理的原因.

4)springSecurityFilterChain 进入 DelegatingFilterProxy

上面提到 DelegatingFilterProxy 对 filter 延迟初始化的作用,所以对 delegate 的赋值只发生处理第一个 http request 时。被命名为 springSecurityFilterChain 的 FilterChainProxy 会从 spring context 中被找出来并设置到 DelegatingFilterProxy 的 delegate field。

至此,应该对文首的第一个图能说出点儿什么了吧… …

DelegatingFilterProxy 的 field ‘Filter delegate’ 就是名为springSecurityFilterChain 的 FilterChainProxy实例
而 springSecurityFilterChain 默认包含 16 个SecurityFilterChain


Reference:
[1]: https://www.baeldung.com/spring-web-contexts
[2]: https://docs.spring.io/spring-security/reference/servlet/architecture.html
[3]: https://docs.spring.io/spring-security/reference/servlet/architecture.html#servlet-security-filters