本章介绍 spring-security 过滤器配置类 HttpSecurity,过滤器加载过程,自定义过滤器
| 内容 | 版本 | 
|---|---|
| JDK | 17 | 
| spring-boot-starter-web | 3.2.2 | 
| spring-boot-starter-security | 3.2.2 | 
| spring-security | 6.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






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

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

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


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

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


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


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


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

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

根据提示可以定义过滤器代码如下
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 中,可以参考如下代码

配置自定义过滤器到过滤器链
@Configuration
public class SecurityConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.addFilterBefore(new TenantFilter(), AuthorizationFilter.class);
        return http.build();
    }
}
 上一篇:分布式系统架构介绍