1️⃣ DelegatingFilterProxy
-
属于 Spring Web(Servlet 规范 + Spring Framework) 的类,不是 Spring Security 专属, 它是连接 Servlet 容器中的 Filter 与 Spring 容器中的 Bean 的关键桥梁。
-
它本身是一个标准的
jakarta.servlet.Filter
,但是并不直接做实际的过滤逻辑,而是 把请求委托给 Spring 容器里定义的某个 Bean(通常是一个 Filter 类型的 Bean) 去执行(如FilterChainProxy
)去执行。
存在的意义
- Servlet 容器(如 Tomcat)在启动时,会读取
web.xml
(或ServletContext
注册的 Filter),只能直接加载类实例,无法感知 Spring 容器里的 Bean。 - 而 Spring Security 的核心是 一条 Filter 链(FilterChainProxy),必须交由 Spring 容器管理(便于依赖注入、AOP、配置)。
- 所以:需要
DelegatingFilterProxy
作为适配器,把 Servlet 容器里的 Filter 请求转发给 Spring 容器里的目标 Bean。
简单说: Tomcat → 调用 DelegatingFilterProxy
→ 找到 Spring 容器中的 bean → 委托执行。
工作机制
-
Servlet 容器启动时,
DelegatingFilterProxy
被注册为 Filter。 -
它会从 Spring 容器里找到与自己名字(或配置的名字)相同的 Bean(通常是
FilterChainProxy
)。 -
每次请求进来时:
DelegatingFilterProxy#doFilter(...)
会调用目标 Bean 的doFilter(...)
。- 实际逻辑由 Spring 管理的 Bean 来完成。
java
public class DelegatingFilterProxy extends GenericFilterBean {
private String targetBeanName;
private WebApplicationContext webApplicationContext;
private volatile Filter delegate;
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// 初始化目标 Bean(只做一次)initFilterBean -> this.delegate = this.initDelegate(wac);
Filter delegateToUse = this.delegate;
// 委托目标 Bean 执行过滤逻辑
delegateToUse.doFilter(request, response, filterChain);
}
}
2️⃣ FilterChainProxy
-
角色:Spring Security 的核心入口 Filter。
-
职责:
- 接收请求(由
DelegatingFilterProxy
转发)。 - 内部维护一个 SecurityFilterChain 列表 ,根据 URL 匹配 SecurityFilterChain ,然后依次执行里面的 Security Filter;Spring Security 的总调度器。
- 接收请求(由
FilterChainProxy 是如何被调用的
- Servlet 容器(Tomcat)收到请求。
- Filter 链 执行到
DelegatingFilterProxy
。 - DelegatingFilterProxy#doFilter():
java
Filter delegate = getDelegate(); // 获取 springSecurityFilterChain Bean
delegate.doFilter(request, response, filterChain);
-
delegate
就是FilterChainProxy
实例。 -
所以
FilterChainProxy#doFilter()
被 Servlet 容器调用,传入原始FilterChain
(继续调用 DispatcherServlet 或下一个 Filter)。
FilterChainProxy 内部逻辑
java
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
FirewalledRequest firewallRequest = this.firewall.getFirewalledRequest((HttpServletRequest) request);
HttpServletResponse firewallResponse = this.firewall.getFirewalledResponse((HttpServletResponse) response);
// 找到匹配的 SecurityFilterChain
List<Filter> filters = null;
// 多条 SecurityFilterChain 如何匹配
for (SecurityFilterChain chain : this.filterChains) {
if (chain.matches(request)) {
// 默认只执行第一个匹配的; 所以在配置多个链时,顺序很重要,URL 模式越具体的链应该放前面。
filters = chain.getFilters();
break;
}
}
// 没匹配到 -> 直接放行
if (filters == null || filters.size() == 0) {
this.filterChainDecorator.decorate(chain).doFilter(firewallRequest, firewallResponse);
return;
}
// 如果匹配:
// 创建"重置链",用于恢复请求状态并调用原始 FilterChain
FilterChain reset = (req, res) -> {
// 恢复请求状态,清理 Security Filter 改动。
firewallRequest.reset();
chain.doFilter(req, res); // 调用原始 FilterChain, 其实就是 Servlet 容器原本的 FilterChain(最终会到 DispatcherServlet)。
};
// 创建 VirtualFilterChain,执行 Filters, 最后调用 reset
this.filterChainDecorator.decorate(reset, filters).doFilter(firewallRequest, firewallResponse);
}
SecurityFilterChain 的匹配
SecurityFilterChain
是一个接口,包含一组 Spring Security 的内置 Filter 和 对应一个 URL 配置模式。
java
public interface SecurityFilterChain {
boolean matches(HttpServletRequest request);
List<Filter> getFilters();
}
-
FilterChainProxy 会遍历所有链,使用
RequestMatcher
判断请求是否匹配, 找到第一个匹配的链执行。matches()
通常是DefaultSecurityFilterChain
实现,内部使用RequestMatcher
判断 URL 是否匹配:
javapublic boolean matches(HttpServletRequest request) { return this.requestMatcher.matches(request); }
可以有多个 SecurityFilterChain
(多安全配置),比如:
/api/**
→ JWT 认证的过滤器链/admin/**
→ Session 登录的过滤器链
FilterChainProxy 调用 Filter 的方式
- 通过 VirtualFilterChain 封装原来的 FilterChain。
- 核心是递归调用:
java
private static class VirtualFilterChain implements FilterChain {
private final FilterChain originalChain;// FilterChain resert
private final List<Filter> additionalFilters; // 这一条 SecurityFilterChain 内的所有 Security Filter
private final int size; // Filter 数量
private int currentPosition = 0; // 当前执行到第几个 Filter
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
// 递归终止条件:如果已经执行完 additionalFilters 中的所有 Filter,调用 原始 FilterChain
// 保证请求最终能到 DispatcherServlet 或原始 Filter 链。
if (currentPosition == additionalFilters.size()) {
// 所有 Security Filter 执行完后 -> 继续执行原始 FilterChain,保证请求最终能到达 DispatcherServlet。
originalChain.doFilter(request, response);
return;
}
this.currentPosition++;
// 取出当前 Filter
Filter nextFilter = this.additionalFilters.get(this.currentPosition - 1);
// 调用它的 doFilter, 把 VirtualFilterChain 自身 (this) 作为下一个 FilterChain 传入
nextFilter.doFilter(request, response, this); // 递归
}
}
-
顺序执行
- Security Filter 的执行顺序严格按照
additionalFilters
列表的顺序。 - 这是为什么 Spring Security 中不同 Filter 的顺序很重要(例如 ExceptionTranslationFilter 要在 UsernamePasswordAuthenticationFilter 前面)。
- 若执行过程中抛出认证或授权异常(如
AuthenticationException
),会被ExceptionTranslationFilter
捕获处理,不会继续执行后续 Filter。
- Security Filter 的执行顺序严格按照
-
递归链
- VirtualFilterChain 本质上是 递归调用链 ,每个 Filter 完成后调用
chain.doFilter()
,进入下一层 Filter。
- VirtualFilterChain 本质上是 递归调用链 ,每个 Filter 完成后调用
-
最终回原始链
- 当
currentPosition == size
,执行originalChain.doFilter()
,把请求交回原始的 Servlet FilterChain(进入 DispatcherServlet)。
- 当
3️⃣ 补充,总结
DelegatingFilterProxy 的职责
- 作为 Servlet Filter 注册到 Servlet 容器中,但本身不实现安全逻辑。
- 将请求委托给 Spring 容器中名为
springSecurityFilterChain
的 Bean(即FilterChainProxy
)。 - 默认情况下,Spring Security 会把
FilterChainProxy
注册为一个 名为 "springSecurityFilterChain" 的 Bean。
FilterChainProxy 的创建与注册
- Spring Security 配置:
java
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// HttpSecurity DSL 配置生成 SecurityFilterChain
return http.build();
}
}
-
底层过程:
@EnableWebSecurity
会触发WebSecurityConfiguration
自动配置,注册springSecurityFilterChain
Bean- 类型就是
FilterChainProxy
- FilterChainProxy 的构造器里拿到所有 SecurityFilterChain
- Spring Bean 注册:

java
@Bean(name = "springSecurityFilterChain")
public FilterChainProxy springSecurityFilterChain(List<SecurityFilterChain> chains) {
return new FilterChainProxy(chains);
}
- 这个 Bean 就是 DelegatingFilterProxy 要委托的目标。
DelegatingFilterProxy 调用流程
假设你在 web.xml
或 Spring Boot 默认注册了(一般就自动配置):
java
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
-
Tomcat / Servlet 容器启动:
- 扫描到
DelegatingFilterProxy
- 调用
DelegatingFilterProxy.init()
- 扫描到
DelegatingFilterProxy init() 核心源码逻辑
java
@Override
public void init(FilterConfig filterConfig) {
// 1. Bean 名称,默认为 filter-name
String targetBeanName = getTargetBeanName();
// 2. 从 Spring WebApplicationContext 获取 Bean
this.delegate = obtainWebApplicationContext(filterConfig)
.getBean(targetBeanName, Filter.class);
// delegate 就是 FilterChainProxy 实例
}
delegate
就是 FilterChainProxy Bean- 之后所有请求都委托给这个 Bean:
java
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws ServletException, IOException {
this.delegate.doFilter(request, response, chain); // ✅ 这里调用 FilterChainProxy.doFilter()
}
调用流程图
scss
┌───────────────────────────────┐
│ 客户端请求 │
└───────────────┬───────────────┘
│
▼
Tomcat / Servlet 容器 Filter 链
│
▼
┌───────────────────────────────┐
│ DelegatingFilterProxy (Filter) │
│ init(): 获取 delegate Bean │
│ delegate = springSecurityFilterChain (FilterChainProxy) │
└───────────────┬───────────────┘
│ doFilter(request, response, chain)
▼
┌─────────────────────────┐
│ FilterChainProxy │
│ doFilterInternal(): │
│ 1️⃣ Firewall 防护 │
│ 2️⃣ 匹配 SecurityFilterChain │
│ 3️⃣ 创建 VirtualFilterChain │
│ 4️⃣ 执行 Security Filter 链 │
└───────────────┬─────────┘
│
▼
┌─────────────────────────┐
│ VirtualFilterChain │
│(递归执行每个 Filter) │
│ ┌───────────────┐ │
│ │ SecurityFilter1│ --> chain.doFilter(this)
│ ├───────────────┤
│ │ SecurityFilter2│ --> chain.doFilter(this)
│ └───────────────┘
│
│ 当 currentPosition == size
│ 执行 reset 链
▼
┌───────────────────────────────┐
│ FilterChain reset (lambda) │
│ firewallRequest.reset() │
│ originalChain.doFilter() │ <-- 调用原始 FilterChain
└───────────────┬───────────────┘
│
▼
┌──────────────────────────┐
│ DispatcherServlet / MVC │
│ Controller 业务处理 │
└──────────────────────────┘
reset 链
- 恢复请求状态(firewallRequest.reset());
reset
链就是保证 请求能回到原始处理链 - 调用原始 FilterChain.doFilter() → DispatcherServlet
SecurityFilterChain
- 包含一组 Security Filter + URL 匹配规则
- FilterChainProxy 会找到第一个匹配的链并执行
original FilterChain / DispatcherServlet
- Security 处理完毕后,请求继续执行原始链
- 最终到达 Controller / MVC 逻辑