本章介绍 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(); } }
上一篇:分布式系统架构介绍