spring security中的webSecurity构建FilterChainProxy的逻辑
概述:Spring Security 的核心组件
在深入代码之前,我们先理解几个关键角色:
DelegatingFilterProxy: 这是 Spring 提供的一个标准Servlet过滤器。它的作用是代理(delegate)实际的过滤工作给 Spring IoC 容器中的一个Bean。这是 Spring Security 能够将自身过滤器链集成到Servlet容器(如 Tomcat)的关键。FilterChainProxy: 这是 Spring Security 真正的核心过滤器。它本身就是一个Filter,并且被注册为DelegatingFilterProxy的代理目标。FilterChainProxy内部维护了一个或多个SecurityFilterChain,并根据请求 URL 决定使用哪一个链来处理请求。SecurityFilterChain: 这是一个安全过滤器链的抽象。它包含了一系列用于处理特定请求的Filter(如UsernamePasswordAuthenticationFilter,BasicAuthenticationFilter, FilterSecurityInterceptor等)。一个WebSecurity配置可以创建多个SecurityFilterChain,每个链负责不同的 URL 模式。WebSecurity: 这是一个配置构建器。它的主要职责是创建和配置FilterChainProxy所需的SecurityFilterChain列表。它负责全局的、不针对特定 HTTP 请求的配置,比如设置认证管理器、忽略某些静态资源、配置多个安全规则等。HttpSecurity: 这是WebSecurity的内部助手,专门用于构建针对 HTTP 请求的安全规则。我们平时写的http.authorizeRequests(), http.formLogin()等代码,都是在操作这个HttpSecurity对象。每个HttpSecurity的配置最终会生成一个SecurityFilterChain。
一句话总结关系:@EnableWebSecurity 启动配置 -> WebSecurity (作为总构建器) -> 创建 HttpSecurity (作为具体规则构建器) -> HttpSecurity 构建出 SecurityFilterChain (过滤器链) -> WebSecurity 将所有 SecurityFilterChain 组合并最终创建 FilterChainProxy -> DelegatingFilterProxy 将请求代理给 FilterChainProxy。
启动与初始化:@EnableWebSecurity 的魔法
一切始于 @EnableWebSecurity 注解,@EnableWebSecurity 是一个组合注解,它导入了 WebSecurityConfiguration。这个配置类通过 @Import 引入了 Spring Security 的自动配置和核心 Bean 定义。
关键步骤:
- 创建 WebSecurity Bean: Spring 容器会创建一个名为
springSecurityFilterChain的Bean,其类型是FilterChainProxy。这个Bean的创建和初始化逻辑都在WebSecurityConfiguration中。 - 注册 DelegatingFilterProxy: 同时,一个名为
springSecurityFilterChain的DelegatingFilterProxy会被注册到Servlet容器中。这个代理过滤器的目标(targetBeanName)就是上面创建的FilterChainProxy Bean。 - 设置过滤器顺序: 通过
@Order注解或FilterRegistrationBean,确保DelegatingFilterProxy在过滤器链中有一个合适的顺序(通常是靠前的位置),以便尽早拦截请求。
核心构建者:WebSecurity 与 HttpSecurity 的分工
当你继承 WebSecurityConfigurerAdapter (在较新版本中是直接定义 SecurityFilterChain Bean) 时,你实际上是在和这两个构建器打交道。
WebSecurity (总设计师)
- 职责: 负责全局配置。
- 常用方法:
web.ignoring().antMatchers("/css/**", "/js/**"): 完全忽略某些请求,让它们不经过任何 Spring Security 过滤器。这对于静态资源非常有用,可以提升性能。这些请求甚至不会被DelegatingFilterProxy拦截。web.authenticationManager(): 设置全局的AuthenticationManager,用于认证。web.addFilterBefore(...) / addFilterAfter(...): 在所有SecurityFilterChain的过滤器之前/之后添加自定义过滤器。web.securityContext().requestCache(): 配置请求缓存策略。
HttpSecurity (具体规则制定者)
- 职责: 为特定的 URL 模式配置详细的安全规则。每个
configure(HttpSecurity http)方法(或每个@Bean SecurityFilterChain)都会创建一个独立的HttpSecurity实例。更加详细的请查看spring security中httpSecurity构建DefaultSecurityFilterChain逻辑 - 常用方法 (链式调用):
http.authorizeRequests(): 开始配置授权规则(谁可以访问什么 URL)。http.formLogin(): 配置表单登录。http.csrf(): 配置 CSRF 保护。
关键点:一个 WebSecurity 可以配置多个 HttpSecurity,从而产生多个 SecurityFilterChain。例如:
@Bean
public SecurityFilterChain apiChain(HttpSecurity http) throws Exception {
return http
.securityMatcher("/api/**") // 这个链只匹配 /api/** 的请求
.authorizeRequests(authz -> authz.anyRequest().hasRole("API_USER"))
.httpBasic(withDefaults())
.build();
}
@Bean
public SecurityFilterChain webAppChain(HttpSecurity http) throws Exception {
return http
.authorizeRequests(authz -> authz.anyRequest().authenticated()) // 匹配所有其他请求
.formLogin(withDefaults())
.build();
}
关键产物:SecurityFilterChain 与 SecurityFilterProxy 的构建
构建 SecurityFilterChain
- 收集所有配置的过滤器:
HttpSecurity内部维护一个List<Filter>。在你调用formLogin(), csrf()等方法时,Spring Security 会把对应的过滤器(如UsernamePasswordAuthenticationFilter,CsrfFilter)添加到这个列表中。 - 排序过滤器: 根据过滤器之间的依赖关系(如
CsrfFilter必须在UsernamePasswordAuthenticationFilter之前),对列表进行排序。 - 创建 FilterChain: 将排序后的过滤器列表包装成一个
DefaultSecurityFilterChain对象。这个对象包含两个关键信息:
- 一个
RequestMatcher:用于判断当前请求是否应该由这个链处理(例如,/api/**)。 - 一个
List<Filter>:处理该请求的过滤器列表。
构建 FilterChainProxyWebSecurity 的最终目标是创建 FilterChainProxy。
- 收集所有 SecurityFilterChain:
WebSecurity会收集所有通过HttpSecurity.build()方法创建的SecurityFilterChain Bean,并将它们放入一个列表中。 - 创建 FilterChainProxy:
WebSecurity使用这个SecurityFilterChain列表来实例化FilterChainProxy。 - FilterChainProxy 的内部结构:
- 它持有一个
List<SecurityFilterChain>。 - 它本身实现了
Filter接口,因此可以被Servlet容器调用。 - 它的
doFilter方法是整个安全逻辑的入口。
请求处理流程:FilterChainProxy 如何工作
当一个 HTTP 请求到达应用时,流程如下:
- Servlet 容器: Tomcat 接收到请求,开始执行过滤器链。
- DelegatingFilterProxy: 容器调用
DelegatingFilterProxy的doFilter方法。 - 委托:
DelegatingFilterProxy从 Spring 容器中找到名为springSecurityFilterChain的FilterChainProxy Bean,并调用其doFilter方法,将ServletRequest,ServletResponse和FilterChain传递过去。 - FilterChainProxy.doFilter(request, response, chain): 这是核心逻辑!
- 查找匹配的
SecurityFilterChain: FilterChainProxy遍历它内部维护的SecurityFilterChain列表。对每个链,它会调用其RequestMatcher的matches(request)方法。 - 第一个匹配者胜出: 一旦找到第一个匹配当前请求 URL 的
SecurityFilterChain,就停止查找。 - 执行过滤器链:
FilterChainProxy获取到这个匹配的 SecurityFilterChain 后,会依次执行该链中的所有 Filter。 - 链的末尾: 最后一个过滤器通常是
FilterSecurityInterceptor。它负责最终的授权决策(Access Decision)。它会检查当前用户是否有权限访问请求的资源。如果权限不足,会抛出AccessDeniedException。 - 异常处理: 如果在过滤器链的任何环节抛出认证或授权异常,
FilterChainProxy会有一个专门的ExceptionTranslationFilter来捕获这些异常,并进行处理(例如,重定向到登录页面或返回 403 Forbidden)。
- 请求继续: 如果所有过滤器都成功执行,请求最终会到达
FilterChainProxy构造时传入的原始FilterChain(即 Servlet 容器的后续过滤器链),并最终到达你的Controller。
总结与图解
请求的核心流程图:
+-----------------------------+
| Servlet Container |
| (e.g., Tomcat) |
+-----------------------------+
|
v
+-----------------------------+
| DelegatingFilterProxy | <-- Registered in web.xml/ServletContext
| (targetBeanName: "springSecurityFilterChain") |
+-----------------------------+
| (delegates to)
v
+-----------------------------+
| FilterChainProxy | <-- The real security filter
| (Bean: "springSecurityFilterChain") |
+-----------------------------+
|
| 1. Find matching chain for request URL
v
+-----------------------------+ +-----------------------------+
| SecurityFilterChain 1 | | SecurityFilterChain 2 |
| (matcher: "/api/**") | | (matcher: "/**") |
| - CsrfFilter | | - CsrfFilter |
| - UsernamePasswordFilter | | - FormLoginFilter |
| - FilterSecurityInterceptor | | - FilterSecurityInterceptor |
+-----------------------------+ +-----------------------------+
^
| 2. Execute filters in the chain
|
(Authentication & Authorization happens here)
| 3. If all OK, continue to app
v
+-----------------------------+
| Your Application (Controller)|
+-----------------------------+
FilterChainProxy构建核心流程图:
@EnableWebSecurity
|
v
WebSecurityConfiguration (creates beans)
|
+---> Creates DelegatingFilterProxy (registers with servlet container)
|
+---> Creates WebSecurity (builder)
|
+---> User configures web.ignoring() (global ignores)
|
+---> User defines one or more SecurityFilterChain Beans (via HttpSecurity)
|
+---> HttpSecurity 1 -> build() -> SecurityFilterChain 1 (for /api/\*\*)
| - Adds filters (CsrfFilter, etc.)
| - Configures matchers, authorization rules
|
+---> HttpSecurity 2 -> build() -> SecurityFilterChain 2 (for /\*\*)
- Adds filters (CsrfFilter, FormLoginFilter, etc.)
- Configures matchers, authorization rules
|
+---> WebSecurity collects all SecurityFilterChains
|
+---> Creates FilterChainProxy, injecting the list of SecurityFilterChains
|
+---> DelegatingFilterProxy is configured to delegate to this FilterChainProxy
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)