Spring Security 6.x 过滤器链SecurityFilterChain是如何工作的?
一、背景:为什么需要 SecurityFilterChain?
默认的过滤器链:

1. Servlet Filter 的基础作用
在 Java Web 开发中,Servlet 提供了一个 Filter 机制,用于拦截 HTTP 请求和响应。Filter 是一个链式结构(FilterChain),可以按顺序执行多个过滤器。例如:
- 认证过滤器:检查用户是否登录。
- 鉴权过滤器:检查用户是否有权限访问某个资源。
- 日志过滤器:记录请求信息。
理论上,我们可以直接编写一系列与安全相关的 Filter(如认证、鉴权等),将它们注册到 Servlet 的 FilterChain 中,就可以实现安全功能。既然如此,为什么还需要 Spring Security 的 SecurityFilterChain?这正是初学者常见的疑问。
2. 直接使用 Servlet Filter 的局限性
尽管 Servlet Filter 看起来简单直接,但在实际开发中,尤其是复杂的 Spring 应用中,直接使用 Filter 会遇到以下问题:
- Spring 容器与 Servlet 容器的时间差:Servlet 容器(如 Tomcat)启动时,
Filter会被初始化并注册,而此时 Spring 容器(ApplicationContext)可能还未完全加载,导致Filter无法直接获取 Spring 管理的 Bean。 - 代码重复与维护成本:如果每个安全相关的
Filter都需要手动处理 Spring Bean 的获取,代码会变得冗余,违背依赖注入的原则。 - 灵活性不足:Servlet
Filter的匹配规则仅限于 URL 模式(通过web.xml或@WebFilter配置),无法满足复杂的匹配需求。 - 调试困难:多个
Filter独立运行,调试时难以统一跟踪安全相关的逻辑。
Spring Security 的 SecurityFilterChain 正是为了解决这些问题而设计的。
二、逐步分析 SecurityFilterChain 的必要性
1. 问题 1:如何在 Filter 中获取 Spring 容器中的 Bean?
问题背景
- Servlet 容器启动时,
Filter实例会先被创建并注册到FilterChain中。 - 而 Spring 容器(
ApplicationContext)的 Bean 加载通常在 Servlet 容器启动之后(通过ContextLoaderListener或 Spring Boot 的自动配置)。 - 这导致在
Filter初始化时,Spring 容器中的 Bean(例如认证服务、用户详情服务等)尚未可用,无法直接通过@Autowired注入。
解决方案:DelegatingFilterProxy
Spring 提供了一个特殊的 Filter 实现类 DelegatingFilterProxy,用来解决这一问题:
- 作用:
DelegatingFilterProxy是一个“占位”过滤器,在 Servlet 容器启动时先注册,但不直接执行具体的过滤逻辑。 - 工作原理:
- 在 Servlet 容器启动时,
DelegatingFilterProxy会被注册到FilterChain中。 - 当 HTTP 请求到达时,
DelegatingFilterProxy的doFilter方法会被调用。 - 在
doFilter方法中,DelegatingFilterProxy会从 Spring 容器(ApplicationContext)中动态查找一个真正的FilterBean(通过名称匹配),然后将请求委派给这个 Bean 执行。
- 在 Servlet 容器启动时,
- 代码示例(Spring Boot 自动配置会处理以下内容,无需手动配置):
// 假设 Spring 容器中有一个 Bean 名为 "springSecurityFilterChain"@Beanpublic Filter springSecurityFilterChain() {// 返回真正的 Filter 实例return new SomeSecurityFilter();}
DelegatingFilterProxy会查找名为springSecurityFilterChain的 Bean,并委派给它。
好处:通过这种“委派模式”,DelegatingFilterProxy 解决了 Servlet Filter 和 Spring 容器的时间差问题,允许 Filter 访问 Spring 管理的 Bean。
2. 问题 2:是否可以为每个 Filter 都使用 DelegatingFilterProxy?
问题分析
假设我们为 Spring Security 中的每个安全相关的 Filter(如认证、鉴权、CSRF 保护等)都创建一个独立的 DelegatingFilterProxy,会带来以下问题:
- 代码重复:每个
Filter都需要在doFilter方法中手动从ApplicationContext查找对应的 Bean,代码重复,违背了依赖注入(DI)原则。 - 维护成本高:如果有 10 个安全相关的
Filter,就需要 10 个DelegatingFilterProxy,增加了开发和维护成本。 - 调试复杂:多个独立的
DelegatingFilterProxy分布在FilterChain中,调试时难以统一跟踪。
解决方案:FilterChainProxy
为了解决上述问题,Spring Security 引入了 FilterChainProxy,作为所有 Spring Security 相关 Filter 的统一入口:
- 作用:
FilterChainProxy是 Spring Security 的核心过滤器,负责管理所有安全相关的Filter,并将它们组织成一个逻辑上的过滤器链。 - 工作原理:
- 从 Servlet
FilterChain的角度看,Spring Security 只注册了一个Filter,即DelegatingFilterProxy。 DelegatingFilterProxy将请求委派给FilterChainProxy。FilterChainProxy内部维护一个或多个SecurityFilterChain实例,根据请求的 URL 或其他条件选择合适的SecurityFilterChain来处理请求。
- 从 Servlet
代码示例(Spring Security 内部实现):
public class FilterChainProxy implements Filter {private List<SecurityFilterChain> filterChains;@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {// 根据请求选择合适的 SecurityFilterChainSecurityFilterChain matchingChain = findMatchingChain(request);if (matchingChain != null) {matchingChain.doFilter(request, response);} else {chain.doFilter(request, response); // 继续下一个 Filter}}}
好处:
- 统一入口:所有 Spring Security 的
Filter都通过FilterChainProxy管理,简化了调试。例如,可以在FilterChainProxy的doFilter方法中设置断点,跟踪所有安全相关的逻辑。 - 减少代码重复:只需要一个
DelegatingFilterProxy,避免为每个Filter重复编写查找 Bean 的逻辑。 - 便于扩展:可以在
FilterChainProxy中添加全局逻辑,例如日志记录、防火墙等。
3. 问题 3:如何在 FilterChainProxy 和 SecurityFilterChain 之间协作?
桥梁作用
FilterChainProxy作为统一入口,负责将请求分发给合适的SecurityFilterChain。SecurityFilterChain是 Spring Security 中更细粒度的过滤器链,包含用户通过HttpSecurity配置的各种安全规则(如认证、授权、CSRF 保护等)。
执行流程
- HTTP 请求到达 Servlet 的
FilterChain。 DelegatingFilterProxy触发,委派给FilterChainProxy。FilterChainProxy根据请求(通过RequestMatcher匹配)选择一个SecurityFilterChain。SecurityFilterChain执行用户配置的Filter列表,例如:UsernamePasswordAuthenticationFilter(处理表单登录)。FilterSecurityInterceptor(执行权限检查)。
- 如果请求通过所有
Filter,则继续执行后续的 Servlet 逻辑(例如调用 Controller)。
附加功能:
- 在
SecurityFilterChain的前后,Spring Security 可以添加全局处理逻辑,例如:- 防火墙(
HttpFirewall):防范特定类型的攻击(如路径遍历攻击)。 - 日志记录:记录每个请求的安全处理结果。
- 防火墙(
4. 问题 4:Servlet Filter 的局限性如何解决?
Servlet Filter 的局限性
- 匹配规则单一:Servlet
Filter只能通过 URL 模式进行匹配(例如/api/**),无法支持复杂的条件(如请求头、方法类型等)。 - 配置不灵活:无法动态调整匹配规则或组合多个条件。
解决方案:SecurityFilterChain 和 RequestMatcher
Spring Security 的 SecurityFilterChain 通过 RequestMatcher 接口解决了这些问题:
- 作用:
RequestMatcher是一个接口,用于定义请求匹配规则,Spring Security 提供了多种实现:AntPathRequestMatcher:基于 Ant 风格的 URL 匹配(例如/public/**)。RegexRequestMatcher:基于正则表达式的 URL 匹配。AndRequestMatcher/OrRequestMatcher:组合多个匹配规则。- 自定义
RequestMatcher:可以实现任意复杂的匹配逻辑。
- 示例:
http.securityMatcher(new AntPathRequestMatcher("/api/**")) // 只匹配 /api/** 路径.authorizeHttpRequests((requests) -> requests.anyRequest().authenticated());
- 好处:
- 灵活性:支持复杂的匹配逻辑,例如“仅对 POST 请求的
/admin/**路径进行认证”。 - 可扩展性:通过自定义
RequestMatcher,可以实现任意匹配规则。
- 灵活性:支持复杂的匹配逻辑,例如“仅对 POST 请求的
三、SecurityFilterChain 的必要性总结
SecurityFilterChain 并不是简单地替代 Servlet Filter,而是为了解决直接使用 Filter 的多种问题,提供更强大、灵活和可维护的安全机制。总结其必要性如下:
解决 Spring 容器与 Servlet 容器的时间差:
- 通过
DelegatingFilterProxy,在Filter中动态获取 Spring Bean。
- 通过
减少代码重复,提高可维护性:
- 使用
FilterChainProxy作为统一入口,避免为每个Filter重复编写查找 Bean 的逻辑。
- 使用
便于调试和扩展:
FilterChainProxy提供单一入口,便于跟踪和调试安全逻辑。- 可以在
SecurityFilterChain前后添加全局处理(如防火墙)。
增强灵活性:
- 通过
RequestMatcher,支持复杂的请求匹配规则,超越了 ServletFilter的局限性。
- 通过
模块化和可配置性:
- 用户可以通过
HttpSecurity配置多个SecurityFilterChain,实现模块化的安全策略(例如 API 和 Web 页面使用不同的安全规则)。
- 用户可以通过
四、实际应用中的例子
假设你有一个 Web 应用,需要以下安全规则:
/public/**:公开访问。/api/**:需要 Basic 认证。/admin/**:需要表单登录和管理员权限。
使用 SecurityFilterChain,可以这样配置:
@Configurationpublic class SecurityConfig {@Beanpublic SecurityFilterChain publicFilterChain(HttpSecurity http) throws Exception {http.securityMatcher("/public/**").authorizeHttpRequests((requests) -> requests.anyRequest().permitAll());return http.build();}@Beanpublic SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception {http.securityMatcher("/api/**").authorizeHttpRequests((requests) -> requests.anyRequest().authenticated()).httpBasic(withDefaults());return http.build();}@Beanpublic SecurityFilterChain adminFilterChain(HttpSecurity http) throws Exception {http.securityMatcher("/admin/**").authorizeHttpRequests((requests) -> requests.anyRequest().hasRole("ADMIN")).formLogin(withDefaults());return http.build();}}
- 执行流程:
- 请求到达
FilterChainProxy。 - 根据
securityMatcher,选择合适的SecurityFilterChain:/public/home->publicFilterChain-> 直接通过。/api/data->apiFilterChain-> 触发 Basic 认证。/admin/dashboard->adminFilterChain-> 触发表单登录并检查角色。
- 如果没有匹配的
SecurityFilterChain,则继续执行后续逻辑。
- 请求到达
五、总结
Spring Security 的 SecurityFilterChain 是对 Servlet Filter 的增强和封装,解决了直接使用 Filter 的多个问题,包括容器时间差、代码重复、调试困难和匹配规则的局限性。通过 DelegatingFilterProxy、FilterChainProxy 和 SecurityFilterChain 的协作,Spring Security 提供了一个强大、灵活且易于维护的安全框架。
借用网络上的一张图,原博文链接:http://www.fullstackyang.com/springan-quan-kuang-jia-xi-lie-sessionguan-li/

