Spring Security 默认配置源码分析
在 Spring Security 的官方文档中,说明了,它的配置为以下的默认实现。
1 |
|
说明一下什么是使用表单的授权方式,什么是使用基本授权方式,注意这里的授权其实是认证))
表单认证是基于页面表单的用户身份验证方式,适用于传统 Web 应用(有前端页面的场景)。默认行为就会自动生成一个简单的登录页面(包含用户名输入框、密码输入框、提交按钮)。
可以按照下面这样自定义配置:
1 | http.formLogin(form -> form |
HTTP Basic 认证就是基本认证,是基于 HTTP
协议规范的认证方式,适用于 API
接口(无前端页面的场景),通过请求头传递认证信息。当未认证用户访问受保护资源时,服务器不会重定向到登录页,而是返回
401 Unauthorized 响应,并在响应头中添加
WWW-Authenticate: Basic realm="Realm"。
客户端(如浏览器、Postman、前端 Ajax)收到响应后,会弹出一个系统级别的登录弹窗(由浏览器 / 客户端生成,非自定义页面)。认证信息通过 HTTP 头传递(Base64 编码,不加密,生产环境需配合 HTTPS 使用)。无默认登出机制(需手动清除请求头或关闭客户端)。
而默认的15(16)个过滤器就是这些,好像我注销了一个配置,就有一个没装上
在 Spring Security
中,这些默认的过滤器在不同的配置器(Configurer)中被创建和配置,然后由HttpSecurity进行统一管理和组装,最终形成DefaultSecurityFilterChain
。关于这个的内容下面会细说
Spring Security 的自动配置
HttpSecurity 中加载了什么
之前我们讲解的初始化配置只是在很简单的层面上做了一些介绍,方便后面的学习,在这里我们将有条理的分析整个Spring Security 自动配置
HttpSecurity 是 Spring Security 中配置 HTTP
安全规则的核心入口类
HttpSecurity 这个 bean
算是最基础的底层配置了,它是Spring
Security各种配置的基础,这个bean是Spring
Security自动加载的,并且同时会默认帮我们完成了Spring
Security完整功能的各项配置,我们先找到这个bean加载的位置:
在HttpSecurityConfiguration类中,加载了HttpSecurity
Spring Security 对 Web 应用的保护,本质是对 “HTTP 请求”
的拦截与规则校验 。HttpSecurity 就是负责定义这些
“拦截规则” 的核心类,包括:
哪些请求需要认证?
由
AuthorizeHttpRequestsConfigurer实现,AuthorizeHttpRequestsConfigurer是处理请求授权的核心配置器,其内部的AuthorizationManagerRequestMatcherRegistry提供了requestMatchers()、permitAll()、authenticated()等方法,用于定义 “哪些请求需要认证”。1
2
3
4
5
6
7
8
9
10
11// HttpSecurity 中与请求授权相关的方法
public HttpSecurity authorizeHttpRequests(Customizer<AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry> authorizeHttpRequestsCustomizer) throws Exception {
ApplicationContext context = this.getContext();
// 获取或创建 AuthorizeHttpRequestsConfigurer 配置器
AuthorizeHttpRequestsConfigurer<HttpSecurity> configurer = (AuthorizeHttpRequestsConfigurer) this.getOrApply(new AuthorizeHttpRequestsConfigurer(context));
// 通过 Customizer 自定义授权规则(如哪些路径允许匿名、哪些需要认证)
authorizeHttpRequestsCustomizer.customize(configurer.getRegistry());
return this;
}实际开发中,我们通过链式调用配置规则,例如
1
2
3
4
5http.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll() // 公开路径,无需认证
.requestMatchers("/admin/**").hasRole("ADMIN") // 管理员角色可访问
.anyRequest().authenticated() // 其他请求必须认证
);- 这些配置最终会转换为
Filter(如FilterSecurityInterceptor),在请求到达时拦截并校验权限。
- 这些配置最终会转换为
用什么方式认证(表单登录、HTTP Basic、OAuth2 等)?
HttpSecurity通过不同的配置器支持多种认证方式,以下是最常用的几种:表单登录(
formLogin)1
2
3
4
5
6
7
8// 表单登录配置方法
public HttpSecurity formLogin(Customizer<FormLoginConfigurer<HttpSecurity>> formLoginCustomizer) throws Exception {
// 获取或创建 FormLoginConfigurer 配置器(负责表单登录逻辑)
FormLoginConfigurer<HttpSecurity> configurer = (FormLoginConfigurer) this.getOrApply(new FormLoginConfigurer());
// 自定义表单登录配置(如登录页URL、成功跳转页等)
formLoginCustomizer.customize(configurer);
return this;
}FormLoginConfigurer是处理表单登录的配置器,负责:- 生成默认登录页(或指定自定义登录页
loginPage("/login")); - 处理登录请求(默认
/login)、成功 / 失败跳转; - 生成
UsernamePasswordAuthenticationFilter过滤器,拦截登录请求并校验用户名密码。
- 生成默认登录页(或指定自定义登录页
HTTP Basic 认证
1
2
3
4
5
6
7
8// HTTP Basic 认证配置方法
public HttpSecurity httpBasic(Customizer<HttpBasicConfigurer<HttpSecurity>> httpBasicCustomizer) throws Exception {
// 获取或创建 HttpBasicConfigurer 配置器(负责HTTP Basic认证)
HttpBasicConfigurer<HttpSecurity> configurer = (HttpBasicConfigurer) this.getOrApply(new HttpBasicConfigurer());
// 自定义HTTP Basic配置(如 Realm 名称)
httpBasicCustomizer.customize(configurer);
return this;
}OAuth2 登录
1
2
3
4
5
6// OAuth2 登录配置方法(第三方登录,如GitHub、微信)
public HttpSecurity oauth2Login(Customizer<OAuth2LoginConfigurer<HttpSecurity>> oauth2LoginCustomizer) throws Exception {
OAuth2LoginConfigurer<HttpSecurity> configurer = (OAuth2LoginConfigurer) this.getOrApply(new OAuth2LoginConfigurer());
oauth2LoginCustomizer.customize(configurer);
return this;
}OAuth2LoginConfigurer用于配置 OAuth2/OpenID Connect 登录,支持第三方认证;- 会生成
OAuth2LoginAuthenticationFilter,处理 OAuth2 回调请求并完成认证。
认证后如何授权(基于角色、权限)?
授权逻辑与 “哪些请求需要认证” 同属一个配置器,核心是通过
AuthorizationManager校验用户权限是否匹配请求要求。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// AuthorizeHttpRequestsConfigurer 内部类,用于定义授权规则
public class AuthorizationManagerRequestMatcherRegistry {
// 例如:配置某个路径需要特定角色
public AuthorizationManagerRequestMatcherRegistry hasRole(String role) {
// 内部会创建基于角色的 AuthorizationManager
return this.access(this.roleHierarchyAuthoritiesMapper(role));
}
// 配置某个路径允许匿名访问
public AuthorizationManagerRequestMatcherRegistry permitAll() {
return this.access(AuthenticatedAuthorizationManager.permitAll());
}
// 配置其他请求必须认证
public AuthorizationManagerRequestMatcherRegistry authenticated() {
return this.access(AuthenticatedAuthorizationManager.authenticated());
}
}- 授权规则最终会转换为
AuthorizationManager(权限管理器),在请求拦截时校验:- 用户是否拥有
hasRole("ADMIN")要求的角色; - 请求是否符合
permitAll()(无需认证)或authenticated()(必须认证)。
- 用户是否拥有
- 底层由
FilterSecurityInterceptor过滤器执行校验,不通过则抛出AccessDeniedException。
- 授权规则最终会转换为
如何处理跨站请求伪造(CSRF)、会话、异常?
1
2
3
4
5
6
7
8
9// CSRF 防护配置方法
public HttpSecurity csrf(Customizer<CsrfConfigurer<HttpSecurity>> csrfCustomizer) throws Exception {
ApplicationContext context = this.getContext();
// 获取或创建 CsrfConfigurer 配置器(负责CSRF防护)
CsrfConfigurer<HttpSecurity> configurer = (CsrfConfigurer) this.getOrApply(new CsrfConfigurer(context));
// 自定义CSRF配置(如开启/关闭、令牌存储方式)
csrfCustomizer.customize(configurer);
return this;
}如何处理会话?
sessionManagement配置1
2
3
4
5
6
7
8// 会话管理配置方法
public HttpSecurity sessionManagement(Customizer<SessionManagementConfigurer<HttpSecurity>> sessionManagementCustomizer) throws Exception {
// 获取或创建 SessionManagementConfigurer 配置器(负责会话管理)
SessionManagementConfigurer<HttpSecurity> configurer = (SessionManagementConfigurer) this.getOrApply(new SessionManagementConfigurer());
// 自定义会话配置(如会话创建策略、超时时间)
sessionManagementCustomizer.customize(configurer);
return this;
}如何处理异常
exceptionHandling配置1
2
3
4
5
6
7
8// 异常处理配置方法
public HttpSecurity exceptionHandling(Customizer<ExceptionHandlingConfigurer<HttpSecurity>> exceptionHandlingCustomizer) throws Exception {
// 获取或创建 ExceptionHandlingConfigurer 配置器(负责异常处理)
ExceptionHandlingConfigurer<HttpSecurity> configurer = (ExceptionHandlingConfigurer) this.getOrApply(new ExceptionHandlingConfigurer());
// 自定义异常处理(如认证失败、授权失败的响应)
exceptionHandlingCustomizer.customize(configurer);
return this;
}ExceptionHandlingConfigurer用于配置认证 / 授权过程中的异常处理,例如:- 认证失败(
authenticationEntryPoint):配置未认证用户访问受保护资源时的响应(如跳转登录页或返回 401 JSON); - 授权失败(
accessDeniedHandler):配置已认证用户权限不足时的响应(如跳转拒绝页或返回 403 JSON)。
- 认证失败(
- 会生成
ExceptionTranslationFilter过滤器,捕获并处理认证 / 授权异常。
所以说,HttpSecurity
基于建造者模式设计,同时通过
配置器(Configurer)对不同安全模块进行解耦,上面说的都是配置器,每个配置器负责一个细分领域的配置
然后这些配置器最终会生成对应的Filter(过滤器),由HttpSecurity统一组装为DefaultSecurityFilterChain,在
HTTP 请求到达时按顺序拦截并应用规则,实现对 Web 应用的安全保护。
| 设计元素 | 作用 |
|---|---|
| 建造者(Builder) | HttpSecurity 本身实现
SecurityBuilder,负责最终构建
DefaultSecurityFilterChain |
| 配置器(Configurer) | 每个配置器对应一个安全模块(如 FormLoginConfigurer
负责表单登录,CsrfConfigurer 负责 CSRF 防护),通过
HttpSecurity 的 xxxConfigurer() 方法接入 |
然后,HttpSecurity 通过不同的配置器,覆盖了 Web
安全的全场景需求,以下是最常用的配置器:
| 配置器方法 | 对应配置器类 | 核心能力 |
|---|---|---|
formLogin() |
FormLoginConfigurer |
配置表单登录(自定义登录页、成功跳转、失败处理等) |
authorizeHttpRequests() |
AuthorizeHttpRequestsConfigurer |
配置请求授权规则(基于角色、权限、IP 等控制访问) |
csrf() |
CsrfConfigurer |
配置CSRF 防护(开启 / 关闭、自定义令牌等) |
logout() |
LogoutConfigurer |
配置登出逻辑(登出 URL、成功跳转、清除会话等) |
sessionManagement() |
SessionManagementConfigurer |
配置会话管理(会话创建策略、超时时间、并发控制等) |
httpBasic() |
HttpBasicConfigurer |
配置HTTP Basic 认证(适合 API 场景) |
oauth2Login() |
OAuth2LoginConfigurer |
配置OAuth2 登录(第三方登录,如 GitHub、微信) |
exceptionHandling() |
ExceptionHandlingConfigurer |
配置异常处理(认证失败、授权失败的页面或 JSON 响应) |
HttpSecurity自动装配的流程
我们一点一点来看看,Spring Security 都帮我们怎么进行了
HttpSecurity 的默认配置了
1 | // HttpSecurityConfiguration 中创建 HttpSecurity 的核心方法 |
首先初始化了AuthenticationManagerBuilder,httpSecurity是重新new了一个authenticationManagerBuilder的,并且我们初始化的authenticationManager是放在
builder 对象里的parentAuthenticationManager属性里的。
然后我们看到httpSecurity的构造方法
可以发现是往一个所谓的共享对象的 Map
容器中放入了authenticationManagerBuilder对象
1 | this.setSharedObject(AuthenticationManagerBuilder.class, authenticationBuilder); |
初始化的时候还放入了spring上下文对象
可以发现httpSecurity的sharedObjects属性里放入了所谓需要共享的对象,另外注意这里requestMatcherConfigurer这个属性也进行了初始化。
接下来就是使用httpSecurity进行了默认配置,在
HttpSecurity 中,通过 getOrApply
方法来获取或应用配置器(如
CsrfConfigurer)。往上看你就会发现几乎所有的配置器都调用的了这个方法进行装配
- 首先尝试从已有的配置器中获取指定类型(这里是
CsrfConfigurer类型)的配置器。 - 如果存在,直接返回;如果不存在,就调用
apply方法来应用这个新的配置器。
而 apply 方法会进一步调用 add
方法,将配置器添加到 configurers
集合中(configurers 是
AbstractConfiguredSecurityBuilder 中的一个
LinkedHashMap,用于存储各种配置器),这样就完成了配置器的注册,后续可以基于这些配置器来构建安全过滤链等安全相关功能。这里实际上就是将上面
new 的 configure 放入了 configurers属性中了。
接下来我们来看过滤器是如何装配的
addFilter方法顾名思义就是添加过滤器的方法
- 首先从
filterOrders中获取要添加的过滤器(如WebAsyncManagerIntegrationFilter)对应的顺序。filterOrders是FilterOrderRegistration类型的对象,内部维护了过滤器类与顺序的映射关系。 - 如果获取不到顺序,会抛出异常,提示需要使用
addFilterBefore或addFilterAfter来指定过滤器顺序;如果获取到顺序,就将过滤器包装成OrderedFilter(包含过滤器实例和顺序)并添加到filters列表中。
最后装完的filters 是一个
ArrayList,用于存储所有添加的过滤器(包装为
OrderedFilter
形式,带有顺序信息)。在构建安全过滤链时,这些过滤器会按照顺序被组织起来,对
HTTP
请求进行安全处理,比如身份验证、授权、跨站请求伪造(CSRF)防护等。
1 | private List<OrderedFilter> filters = new ArrayList(); |
而决定其过滤器顺序的就是filterOrders, 是
FilterOrderRegistration 类型,其内部通过
filterToOrder 等结构维护了不同过滤器类对应的顺序。在
FilterOrderRegistration 的构造方法中,会为各种 Spring
Security 内置的过滤器(如
CsrfFilter、LogoutFilter、UsernamePasswordAuthenticationFilter
等)预先注册好顺序,这样在添加过滤器时,就能根据过滤器类获取到对应的顺序,从而保证过滤器在过滤链中有正确的执行顺序。
这样,不同的过滤器就会按照预先定义的顺序在请求处理流程中依次执行,确保 Spring Security 各项安全功能按正确逻辑生效。
总结一下就是,httpSecurity默认初始化会出事后一个authenticationManager对象并放入一个authenticationManagerBuilder对象中,随后这个
builder 对象会放入 httpSecurity 对象的
sharedObjects属性中; 然后 httpSecurity
会创建类如csrf,exceptionHandling等等的配置器,随后也放入 sharedObjects
属性中。额案后将配置器添加到 configurers
集合中,之后再搭建过滤器链,从 filterOrders
中获取要添加的过滤器,在构建安全过滤链时,这些过滤器会按照顺序被组织起来,实现其功能,这样就联系上了前面进行的
16 个默认过滤器的装配和各种配置的初始化。
HttpSecurity如何构建过滤器链
HttpSecurity如何构建DefaultSecurityFilterChain过滤器链
那么其实HttpSecurity 的使命是构建
DefaultSecurityFilterChain(安全过滤链),流程分为两步
配置阶段:通过配置器定义规则
开发者通过 HttpSecurity 提供的配置器方法(如
formLogin()、authorizeHttpRequests()),声明各类安全规则:
1 |
|
每个配置器(如
FormLoginConfigurer、AuthorizeHttpRequestsConfigurer)会将配置转换为具体的
Filter(过滤器),并注册到 HttpSecurity 中。
构建阶段:生成安全过滤链
当调用 http.build() 时,HttpSecurity
会执行:
- 收集所有配置器生成的 Filter;
- 按照预设顺序(由
FilterOrderRegistration管理)排序 Filter; - 结合请求匹配规则(
RequestMatcher),封装为DefaultSecurityFilterChain; - 将
DefaultSecurityFilterChain注册到 Spring Security 过滤器链中,对 HTTP 请求进行拦截校验。
我们展开说一下,HttpSecurity 继承自
AbstractConfiguredSecurityBuilder,其 build()
方法会触发配置器的初始化和过滤器的收集。
收集所有配置器生成的 Filter
核心逻辑在 AbstractConfiguredSecurityBuilder 的
doBuild() 方法中,该方法会依次调用所有配置器(如
CsrfConfigurer、FormLoginConfigurer 等)的
init() 和 configure()
方法,配置器在这些方法中生成对应的过滤器并添加到
HttpSecurity 的 filters 列表中。
1 |
|
配置器生成过滤器的示例(以 CsrfConfigurer
为例),CsrfConfigurer 在 configure()
方法中创建 CsrfFilter 并添加到 HttpSecurity
的过滤器列表:
1 |
|
按照预设顺序排序 Filter
然后来到了第二步,过滤器的排序由 FilterOrderRegistration
管理,最终在 HttpSecurity 的 performBuild()
方法中完成排序。
1 |
|
FilterOrderRegistration
预先定义了所有内置过滤器的顺序
封装为
DefaultSecurityFilterChain
排序完成后,HttpSecurity
会将过滤器列表与请求匹配规则(RequestMatcher)结合,创建
DefaultSecurityFilterChain
实例。核心就是最后一步,前面都是排序
1 |
|
DefaultSecurityFilterChain 的构造方法如下
1 | public class DefaultSecurityFilterChain implements SecurityFilterChain { |
注册到 Spring Security 过滤器链
DefaultSecurityFilterChain 生成后,会被注册到
FilterChainProxy 中,而 FilterChainProxy
作为一个顶级过滤器(Filter)被 Spring
容器管理,最终拦截所有 HTTP 请求并应用对应的安全过滤链。
FilterChainProxy
会根据请求匹配规则(RequestMatcher)选择对应的
DefaultSecurityFilterChain 处理请求:
1 | public class FilterChainProxy extends GenericFilterBean { |
HttpSecurity如何初始化SecurityFilterChain过滤器链
先回忆一下 Spring Security
的过滤器叫FilterChainProxy,其中存储过滤器的属性叫filterChains,集合里元素的类型时SecurityFilterChain:
因此,我们前面做了那么多,肯定是为了这个SecurityFilterChain来做准备的,下面我们看
SpringBootWebSecurityConfiguration 这个类
进入到这个方法也是很熟悉啊,我们之前说的csrf()、formLogin()
等配置方法 实现模式完全一致,也是做了通过
配置器(Configurer)
收集用户的安全配置的工作(如授权规则、CSRF
开关、登录页设置等),并在后续的 build()
阶段由配置器生成对应的过滤器,最终整合到安全过滤链中。
也是执行了getOrApply来管理配置器
1 | public HttpSecurity authorizeHttpRequests(Customizer<AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry> authorizeHttpRequestsCustomizer) throws Exception { |
管中窥豹,我们可以得出,Spring Security 通过这种 “配置器模式 + 链式调用” 的设计,将分散的安全配置(授权、认证、防护等)统一管理,既保证了扩展性(可自定义配置器),又简化了使用方式(链式 API)。
从这个类结构图中我们不难发现,HttpSecurity和AuthenticationManagerBuilder都是这个
builder 类的子类,所以说实现的逻辑都是一样的,但是,我们
HttpSecurity 的构建就要复杂一点了
前面我们知道了,httpSecurity初始化的时候创建了很多
configure 并且最终是放入到他的 map 集合中的,之前我们提到了
doBuild()方法实现了配置器生成对应的过滤器然后装配的,那么核心的流程就涉及到init()
和 configure() 方法了,他们定义在
AbstractConfiguredSecurityBuilder
类中,是构建安全组件的核心方法。
init() 方法对所有已注册的
SecurityConfigurer(如
CsrfConfigurer、AuthorizeHttpRequestsConfigurer
等)进行初始化操作。在初始化阶段,配置器可以做一些前置准备工作,比如设置一些基础的配置参数、初始化内部依赖等,但还不会实际生成过滤器等核心安全组件。可以看到它在构建过程的早期阶段,为后续的配置阶段做准备。而
beforeinit()则涉及到了更早期的操作,类似 AOP 的前置消息
1 | private void init() throws Exception { |
configure() 方法调用每个 SecurityConfigurer
的 configure
方法,让配置器根据用户的配置(比如授权规则、CSRF
防护开关等)来生成对应的安全组件,像各种过滤器(CsrfFilter、FilterSecurityInterceptor
等)就是在这个阶段由配置器创建并添加到 HttpSecurity 的
filters 列表中的,可以看到他执行在 init()
方法执行之后,是配置器实际发挥作用、生成安全组件的关键阶段。
1 | private void configure() throws Exception { |
init方法和configure方法都是遍历的configurers然后执行每一个configure的配置方法的,configurers
是一个 存储所有安全配置器的容器,定义如下:
1 | // AbstractConfiguredSecurityBuilder 中定义 |
- 这是一个
LinkedHashMap,键是配置器的类型(Class),值是该类型的配置器列表(通常一个类型只有一个配置器)。 - 目的是按类型管理所有注册到
HttpSecurity中的配置器(如CsrfConfigurer、AuthorizeHttpRequestsConfigurer等),方便后续遍历和操作。
init() 和 configure() 方法中遍历的
configurers,正是通过 getConfigurers()
方法提取的:
1 | // AbstractConfiguredSecurityBuilder 中定义 |
- 作用:将
configurers中按类型分组的配置器,汇总为一个扁平的Collection,供init()和configure()遍历。 - 例如:如果注册了
CsrfConfigurer、FormLoginConfigurer、AuthorizeHttpRequestsConfigurer,getConfigurers()会返回包含这三个配置器的集合。
所有配置器(如 CsrfConfigurer)都实现了
SecurityConfigurer 接口(通常继承
SecurityConfigurerAdapter),因此都有 init()
和 configure() 方法。我们挑CsrfConfigurer
方法来实际看一下
在 HttpSecurity 中,通过 http.csrf()
方法触发 CsrfConfigurer 的创建与注册
1 | public CsrfConfigurer<HttpSecurity> csrf() throws Exception { |
getOrApply(new CsrfConfigurer(context)):若已存在CsrfConfigurer,直接返回;否则新建并注册到configurers容器中。
CsrfConfigurer 虽未显式重写
init(),但会继承父类 AbstractHttpConfigurer 的
init()(空实现,可按需重写)。若有初始化逻辑,会在此阶段执行,新版本中,init()的流程貌似都交给了大家来处理
CsrfConfigurer 的 configure()
是核心,负责创建 CsrfFilter 并注册到
HttpSecurity 的过滤器链:
1 |
|
当调用 http.build() 时,进入 performBuild()
阶段,最终参与 SecurityFilterChain 构建:
1 | protected DefaultSecurityFilterChain performBuild() { |
这里我们看到,它先把
filter里面的过滤器排序,遍历然后放入到sortedFilters,最后创建了一个DefaultSecurityFilterChain对象,至此,一个SecurityFilterChain创建完毕,这里构造方法里还有个requestMatcher属性留意一下,其实就是
Spring Security
的FilterChainProxy中的filterChains是一个集合,所以支持多个,那当有多个SecurityFilterChain时,一个请求进来会使用哪个SecurityFilterChain就是由这个requestMatcher决定的
此时,一个完整的 SecurityFilterChain 诞生了:它包含
排序后的过滤器列表(如
CsrfFilter、UsernamePasswordAuthenticationFilter
等)和
请求匹配规则(requestMatcher)。
在 Spring Security 启动时,所有 HttpSecurity 构建的
DefaultSecurityFilterChain 会被收集到
FilterChainProxy 的 filterChains 集合中
当用户发送请求(如
POST /web/user)时,流程进入运行阶段,核心是通过
requestMatcher 选择合适的过滤链:
所有请求会先经过 FilterChainProxy 的
doFilter 方法,这是 Spring Security 的 “守门人
FilterChainProxy 的 doFilter
方法接收请求(Spring Security 过滤链的 “总入口”),是请求进入 Spring
Security
过滤链的第一步,核心逻辑如下,它作为所有安全过滤逻辑的入口,通过
doFilterInternal 方法进入真正的过滤链匹配与执行流程
在 doFilterInternal 方法中,会调用
getFilters 方法筛选出与当前请求匹配的
SecurityFilterChain, getFilters
方法遍历 filterChains 集合,通过每个链的
requestMatcher 判断是否匹配当前请求:
1 | private void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { |
getFilters 方法会遍历所有
SecurityFilterChain,通过 requestMatcher
判断是否匹配当前请求,一旦找到匹配的
SecurityFilterChain,其包含的过滤器会按顺序执行
其中chain.matches(request) —— 每个
SecurityFilterChain 都有自己的
requestMatcher(请求匹配器),只有当请求与
requestMatcher 匹配时,才会使用该链的过滤器。
那么FilterChainsProxy是从哪里来的呢,FilterChainProxy
是 Spring Security
过滤链的顶层代理过滤器,它的创建和注册与
WebSecurity 密切相关
WebSecurity 是 Spring Security
中管理全局安全过滤链的核心构建器(继承自
AbstractConfiguredSecurityBuilder),它的
performBuild() 方法最终会创建 FilterChainProxy
实例,代码如下
1 | protected Filter performBuild() throws Exception { |
也就是说,FilterChainProxy 是 WebSecurity
在 performBuild()
方法中主动创建的,它的构造参数是所有收集到的
SecurityFilterChain,而WebSecurity
本身的初始化和 FilterChainProxy 的创建,依赖于 Spring
Security 的自动配置机制,核心流程如下:
当我们在项目中添加
@EnableWebSecurity注解时,会导入WebSecurityConfiguration配置类,这个类是WebSecurity的 “孵化器”。在
WebSecurityConfiguration中,会通过@Bean方法创建WebSecurity对象,并为其配置必要的依赖(如ObjectPostProcessor、ApplicationContext等):
然后,其中我们通过
SecurityConfiguration中定义的SecurityFilterChainBean,会被WebSecurityConfiguration自动收集,这个方法也就是接收并存储外部配置好的SecurityFilterChain列表
然后通过这个方法过滤器被添加,通过
webSecurity.addSecurityFilterChainBuilder(...)方法添加到WebSecurity的securityFilterChainBuilders列表中(对应WebSecurity源码中的securityFilterChainBuilders集合)。
最后,当 Spring 容器初始化时,会调用
WebSecurity的build()方法(继承自AbstractSecurityBuilder),最终执行performBuild()方法,创建FilterChainProxy并作为@Bean注册到 Spring 容器中。而 webSecurity 和httpSecurity 也是同一个父类,因此 webSecurity 的 build 方法也是同样的逻辑至此,FilterChainsProxy也创建完毕了。
最后,FilterChainProxy 作为 Spring 管理的
Filter 类型 Bean,会被 Spring 的
DelegatingFilterProxy 代理,并注册到 Servlet 容器(如
Tomcat)的过滤器链中。
流程如下:
Spring 容器启动时,
DelegatingFilterProxy作为 Servlet 过滤器被注册(通过AbstractSecurityWebApplicationInitializer自动配置)。DelegatingFilterProxy会从 Spring 容器中查找名为springSecurityFilterChain的FilterBean(默认就是WebSecurity构建的FilterChainProxy)。当请求到达 Servlet 容器时,会先经过
DelegatingFilterProxy,再转发给FilterChainProxy执行实际的安全过滤逻辑。
然后我们就进行梳理HttpSecurity 初始化
SecurityFilterChain 过滤器链的流程
当调用 http.build()(HttpSecurity 继承自
SecurityBuilder,build
方法用于构建最终的安全组件)时,会触发以下关键步骤来初始化
SecurityFilterChain:
执行
init()方法,遍历所有注册到HttpSecurity的SecurityConfigurer,调用它们的init方法,完成配置器的初始化准备。执行
configure()方法,再次遍历所有SecurityConfigurer,调用它们的configure方法。在这个过程中,各个配置器会根据自身的配置逻辑,生成对应的过滤器,并将这些过滤器添加到HttpSecurity的filters列表中。例如CsrfConfigurer会创建CsrfFilter并添加到filters;AuthorizeHttpRequestsConfigurer会创建FilterSecurityInterceptor来处理授权规则,并添加到filters。
构建
DefaultSecurityFilterChain,在HttpSecurity的performBuild方法中,会对filters列表中的过滤器按照预设的顺序(由FilterOrderRegistration管理)进行排序,然后结合请求匹配器(RequestMatcher,用于判断哪些请求需要经过该过滤链),创建DefaultSecurityFilterChain实例注册
SecurityFilterChain,生成的DefaultSecurityFilterChain会被注册到FilterChainProxy中。FilterChainProxy是 Spring Security 过滤器链的代理,它会根据请求的匹配情况,选择对应的SecurityFilterChain来处理请求,从而实现对 HTTP 请求的安全拦截与校验。
所以说,HttpSecurity 初始化
SecurityFilterChain 过滤器链的过程,是通过
init()
方法初始化配置器,configure()方法让配置器生成过滤器,再对过滤器排序并结合请求匹配器构建
DefaultSecurityFilterChain,最后将其注册到
FilterChainProxy 中,以此来实现对 HTTP 请求的安全过滤。






