相关推荐recommended
spring-security 过滤器 (三)
作者:mmseoamin日期:2024-02-28

spring-security过滤器

  • 版本信息
  • 过滤器配置
    • 过滤器配置相关类图
    • 过滤器加载过程
      • 创建 HttpSecurity Bean 对象
      • 创建过滤器
      • 过滤器作用
        • ExceptionTranslationFilter
        • 自定义过滤器

          本章介绍 spring-security 过滤器配置类 HttpSecurity,过滤器加载过程,自定义过滤器

          版本信息

          内容版本
          JDK17
          spring-boot-starter-web3.2.2
          spring-boot-starter-security3.2.2
          spring-security6.2.1

          过滤器配置

          过滤器配置相关类图

          过滤器链由HttpSecurity的配置类配置生成的,在HttpSecurity.build()的时候添加至过滤器链,主要的配置类如下

          org.springframework.security.config.annotation.web.configurers.CsrfConfigurer
          org.springframework.security.config.annotation.web.configurers.ExceptionHandlingConfigurer
          org.springframework.security.config.annotation.web.configurers.HeadersConfigurer
          org.springframework.security.config.annotation.web.configurers.SessionManagementConfigurer
          org.springframework.security.config.annotation.web.configurers.SecurityContextConfigurer
          org.springframework.security.config.annotation.web.configurers.RequestCacheConfigurer
          org.springframework.security.config.annotation.web.configurers.AnonymousConfigurer
          org.springframework.security.config.annotation.web.configurers.ServletApiConfigurer
          org.springframework.security.config.annotation.web.configurers.LogoutConfigurer
          org.springframework.security.config.annotation.web.configurers.CorsConfigurer
          

          spring-security 过滤器 (三),在这里插入图片描述,第1张

          过滤器加载过程

          创建 HttpSecurity Bean 对象

          1. SpringBoot 自动装载类 org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration

            spring-security 过滤器 (三),在这里插入图片描述,第2张

          2. @Import 导入 org.springframework.boot.autoconfigure.security.servlet.SpringBootWebSecurityConfiguration

            spring-security 过滤器 (三),在这里插入图片描述,第3张

          3. Spring Security 核心注解类 @EnableWebSecurity

            spring-security 过滤器 (三),在这里插入图片描述,第4张

          4. @Import 导入 org.springframework.security.config.annotation.web.configuration.HttpSecurityConfiguration

            spring-security 过滤器 (三),在这里插入图片描述,第5张

          5. 在HttpSecurityConfiguration 配置类中开始创建 HttpSecurity 的bean 对象

            spring-security 过滤器 (三),在这里插入图片描述,第6张

            可以在 org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder#add 方法中加个断点,看初始化添加了多少个配置类

            spring-security 过滤器 (三),在这里插入图片描述,第7张

            配置类还可以扩展的,基于SPI扩展 org.springframework.security.config.annotation.web.configuration.HttpSecurityConfiguration#applyDefaultConfigurers

            spring-security 过滤器 (三),在这里插入图片描述,第8张

            从这段代码可以看出,可以自定义过滤器的配置类,对扩展开放√

          创建过滤器

          1. Spring Boot 自动装载在之前已分析,直接定位到 org.springframework.boot.autoconfigure.security.servlet.SpringBootWebSecurityConfiguration, 在这个类中有创建过滤器链的Bean

            spring-security 过滤器 (三),在这里插入图片描述,第9张

          2. 默认过滤器链编译过程,查看 http.build() 方法

            spring-security 过滤器 (三),在这里插入图片描述,第10张

            首先判断是否已经构建了,防止重复构建。再执行 doBuild() 方法

            spring-security 过滤器 (三),在这里插入图片描述,第11张

            在编译的过程中,会读取之前的配置类,将相关的过滤器添加到过滤器链,查看 configure() 方法

            spring-security 过滤器 (三),在这里插入图片描述,第12张

          3. 在配置类中,创建过滤器类,将过滤器类加载到过滤器链,列举一个配置类org.springframework.security.config.annotation.web.configurers.CsrfConfigurer#configure,其它的配置类和这个相似

            spring-security 过滤器 (三),在这里插入图片描述,第13张

            将过滤器添加到列表 org.springframework.security.config.annotation.web.builders.HttpSecurity#filters

            spring-security 过滤器 (三),在这里插入图片描述,第14张

          4. 构建过滤器链,org.springframework.security.config.annotation.web.builders.HttpSecurity#performBuild

            spring-security 过滤器 (三),在这里插入图片描述,第15张

          过滤器作用

          ExceptionTranslationFilter

          官网介绍 https://docs.spring.io/spring-security/reference/servlet/architecture.html#servlet-exceptiontranslationfilter

          spring-security 过滤器 (三),在这里插入图片描述,第16张

          spring-security 过滤器 (三),在这里插入图片描述,第17张

          注意,执行顺序在 ExceptionTranslationFilter 之后的过滤器才会捕获到异常,并进行异常处理。默认过滤器的顺序如图所示,在 ExceptionTranslationFilter 之后的过滤器只有 org.springframework.security.web.access.intercept.AuthorizationFilter,该过滤器抛出的异常可以被异常过滤器捕获到

          spring-security 过滤器 (三),在这里插入图片描述,第18张

          自定义过滤器

          参考官网 https://docs.spring.io/spring-security/reference/servlet/architecture.html#adding-custom-filter,提示部分的内容挺好的

          spring-security 过滤器 (三),在这里插入图片描述,第19张

          根据提示可以定义过滤器代码如下

          import jakarta.servlet.FilterChain;
          import jakarta.servlet.ServletException;
          import jakarta.servlet.http.HttpServletRequest;
          import jakarta.servlet.http.HttpServletResponse;
          import org.springframework.web.filter.OncePerRequestFilter;
          import java.io.IOException;
          import java.nio.file.AccessDeniedException;
          public class TenantFilter extends OncePerRequestFilter {
              @Override
              protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
                                              FilterChain filterChain) throws ServletException, IOException {
                  String tenantId = request.getHeader("X-Tenant-Id");
                  boolean hasAccess = isUserAllowed(tenantId);
                  if (hasAccess) {
                      filterChain.doFilter(request, response);
                      return;
                  }
                  throw new AccessDeniedException("Access denied");
              }
              private boolean isUserAllowed(String tenantId) {
                  // TODO check
                  return false;
              }
          }
          

          避免过滤器注册到 Tomcat 中,可以参考如下代码

          spring-security 过滤器 (三),在这里插入图片描述,第20张

          配置自定义过滤器到过滤器链

          @Configuration
          public class SecurityConfig {
              @Bean
              public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
                  http.addFilterBefore(new TenantFilter(), AuthorizationFilter.class);
                  return http.build();
              }
          }