过滤器链

Spring Security 本质是一个过滤器链。

Spring Security在启动时会加入很多的过滤器。

FilterSecurityInterceptor:是一个方法级的权限过滤器,基本位于过滤器的最底部

最终通过:filterInvocation.getChain().doFilter(filterInvocation.getRequest(), filterInvocation.getResponse()); 进行放行

ExceptionTranslationFilter:是一个异常过滤器,用来处理在认证授权过程中抛出的异常。

UsernamePasswordAuthenticationFilter:对/login的POST请求进行拦截,校验表单中用户名、密码

过滤器加载

如果要使用SpringSecurity,需要配置一个过滤器 DelegatingFilterProxy。

SpringBoot项目中,SpringBoot会默认配置该过滤器,不再需要手工配置。

SpringBoot的自动加载原理:

  1. SpringBoot会加载SecurityFilterAutoConfiguration自动配置类;
  2. 该自动配置类中向容器加入了DelegatingFilterProxyRegistrationBean注册器,并传入了一个目标bean名称springSecurityFilterChain
  3. 该注册器会注册DelegatingFilterProxy过滤器,并将其targetName设置为springSecurityFilterChain。

DelegatingFilterProxy的doFilter()方法中,会调用 initDelegate()方法进行初始化:

initDelegate方法会到容器中寻找targetName的Bean(即beanID=springSecurityFilterChain的bean)。

springSecurityFilterChain的加载:

  1. SecurityFilterAutoConfiguration自动配置类引入了SecurityAutoConfiguration配置类;
  2. SecurityAutoConfiguration配置类引入了WebSecurityEnablerConfiguration配置类;
  3. WebSecurityEnablerConfiguration使用了@EnableWebSecurity注解
  4. @EnableWebSecurity注解引入了WebSecurityConfiguration类
  5. WebSecurityConfiguration配置类中构造 beanID=springSecurityFilterChain的bean时,返回值为WebSecurity的build方法;
  6. WebSecurity最终会创建FilterChainProxy对象,并作为springSecurityFilterChain返回;

FilterChainProxy的doFilter方法中,会调用doFilterInternal(request,response,chain)方法;

doFilterInternal方法调用getFilters获取到所有的过滤器。

获取到的过滤器的来源:

WebSecurityConfiguration的setFilterChainProxySecurityConfigurer方法,先从spring容器中获取过滤器链SecurityFilterChain;

如果WebSecurityConfiguration类中有配置过滤器链,再将该类中配置的过滤器也加入进去;

容器中的过滤器来源:

  1. SecurityFilterAutoConfiguration自动配置类引入了SecurityAutoConfiguration配置类;

  2. SecurityAutoConfiguration配置类引入了SecurityDataConfiguration配置类;

  3. 该类向容器中加入了过滤器链

    1. @Bean
    2. @Order(SecurityProperties.BASIC_AUTH_ORDER)
    3. SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
    4. http.authorizeRequests().anyRequest().authenticated().and().formLogin().and().httpBasic();
    5. return http.build();
    6. }