过滤器链不是凭空出现的,它是由 HttpSecurity 通过 Builder 模式精心构建的。本文将深入剖析 HttpSecurity 的配置收集、排序、构建全流程,以及 AuthenticationManagerBuilder、HttpSecurity、WebSecurity 三者的层级关系。
前言:从一行配置到一个 Filter,中间经历了什么?
在上一篇中,我们了解了 FilterOrderRegistration 如何定义过滤器的执行顺序------那是"宪法"。但宪法只是规定了"谁在前、谁在后",并没有回答一个更根本的问题:
http.formLogin() 这一行配置,最终是如何变成一个活生生的 UsernamePasswordAuthenticationFilter 对象,并被精确地放到过滤器链中正确位置的?
这个问题的答案,藏在 HttpSecurity 的 Builder 模式 构建过程中。这一过程可以分为四个阶段:
- 创建阶段 :
HttpSecurityConfiguration用原型作用域创建HttpSecurity实例 - 收集阶段 :每次调用
http.xxx(),背后的 Configurer 被注册到内部列表 - 构建阶段 :
http.build()触发doBuild三步曲 ------ init → configure → performBuild - 组装阶段 :
WebSecurity收集所有SecurityFilterChain,构建最终的FilterChainProxy
本文将完整拆解这四个阶段的源码。
一、HttpSecurity:过滤器链的"工厂"
1.1 HttpSecurity 的创建:HttpSecurityConfiguration
HttpSecurity 对象由 HttpSecurityConfiguration 负责创建。这个配置类做了两件关键的事:
第一,以 prototype 作用域创建 HttpSecurity:
java
@Bean(HTTPSECURITY_BEAN_NAME)
@Scope("prototype")
HttpSecurity httpSecurity() throws Exception {
// ① 创建 LazyPasswordEncoder(延迟加载,避免循环依赖)
LazyPasswordEncoder passwordEncoder = new LazyPasswordEncoder(this.context);
// ② 构建 AuthenticationManagerBuilder(认证管理器构建器)
AuthenticationManagerBuilder authenticationBuilder =
new DefaultPasswordEncoderAuthenticationManagerBuilder(
this.objectPostProcessor, passwordEncoder);
authenticationBuilder.parentAuthenticationManager(authenticationManager());
authenticationBuilder.authenticationEventPublisher(getAuthenticationEventPublisher());
// ③ 创建 HttpSecurity 实例
HttpSecurity http = new HttpSecurity(
this.objectPostProcessor, authenticationBuilder, createSharedObjects());
// ④ 手动添加 WebAsyncManagerIntegrationFilter(异步请求安全集成)
WebAsyncManagerIntegrationFilter webAsyncManagerIntegrationFilter =
new WebAsyncManagerIntegrationFilter();
webAsyncManagerIntegrationFilter.setSecurityContextHolderStrategy(
this.securityContextHolderStrategy);
// ⑤ 应用默认配置------这就是我们看到的那些"自动开启"的过滤器的来源!
http
.csrf(withDefaults()) // → CsrfFilter
.addFilter(webAsyncManagerIntegrationFilter)
.exceptionHandling(withDefaults()) // → ExceptionTranslationFilter
.headers(withDefaults()) // → HeaderWriterFilter
.sessionManagement(withDefaults()) // → SessionManagementFilter
.securityContext(withDefaults()) // → SecurityContextHolderFilter
.requestCache(withDefaults()) // → RequestCacheAwareFilter
.anonymous(withDefaults()) // → AnonymousAuthenticationFilter
.servletApi(withDefaults()) // → SecurityContextHolderAwareRequestFilter
.apply(new DefaultLoginPageConfigurer<>()); // → DefaultLoginPageGeneratingFilter
http.logout(withDefaults()); // → LogoutFilter
// ⑥ 应用 CORS 配置(如果容器中存在 CorsConfigurationSource Bean)
applyCorsIfAvailable(http);
// ⑦ 通过 SpringFactoriesLoader 加载 META-INF/spring.factories 中的 AbstractHttpConfigurer
applyDefaultConfigurers(http);
return http;
}
关键洞察:
prototype作用域意味着每次注入都会创建新实例,这允许你在同一个应用中配置多条不同的安全过滤器链- 默认配置中显式开启了 10 个安全功能(加上条件加载的 CORS 和 SPI 扩展),这就是为什么 Spring Boot 项目一启动就有 CSRF、表单登录、HTTP Basic 等全套防护,你什么都不配也有一个能用的安全体系
第二,提供组装核心依赖。 为了构建一个功能完备的 HttpSecurity 对象,该配置类负责准备并注入以下关键组件:
| 核心依赖 | 作用 |
|---|---|
| AuthenticationManager | 核心认证管理器,被登录过滤器调用 |
| AuthenticationManagerBuilder | 认证管理器的构建器 |
| ObjectPostProcessor | 对象后处理器:在 Bean 创建后进行生命周期管理和增强 |
| LazyPasswordEncoder | 延迟加载的密码编码器,避免循环依赖 |
1.2 HttpSecurity 的核心数据结构
java
public final class HttpSecurity extends
AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
implements SecurityBuilder<DefaultSecurityFilterChain>,
HttpSecurityBuilder<HttpSecurity> {
private final List<OrderedFilter> filters = new ArrayList<>(); // 未排序的过滤器列表
private RequestMatcher requestMatcher = AnyRequestMatcher.INSTANCE; // 默认匹配所有请求
private AuthenticationManager authenticationManager; // 认证管理器
}
注意 :
filters列表中的元素类型是OrderedFilter(包含 Filter + order 值),而非裸Filter。这个 order 值就是FilterOrderRegistration中定义的序号。OrderedFilter是HttpSecurity的私有内部类,实现了Ordered和Filter接口。
1.3 Configurer 的注册机制:getOrApply → apply → add
当我们调用 http.formLogin() 时,实际执行的是一个三段式调用链。
阶段一:http.xxx() 方法(以 csrf 为例):
java
// HttpSecurity.csrf 方法
public HttpSecurity csrf(Customizer<CsrfConfigurer<HttpSecurity>> csrfCustomizer) throws Exception {
ApplicationContext context = getContext();
// ① getOrApply:获取或创建 CsrfConfigurer(确保单例)
// ② customize:应用你的自定义配置(Lambda 表达式)
csrfCustomizer.customize(getOrApply(new CsrfConfigurer<>(context)));
return HttpSecurity.this; // 链式调用
}
阶段二:getOrApply → apply:
java
private <C extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity>> C
getOrApply(C configurer) throws Exception {
// 先去检查是否已经注册过同类型的 Configurer
C existingConfig = (C) getConfigurer(configurer.getClass());
if (existingConfig != null) {
return existingConfig; // 已存在,直接返回(确保单例)
}
return apply(configurer); // 不存在,注册新的
}
public <C extends SecurityConfigurerAdapter<O, B>> C apply(C configurer) throws Exception {
configurer.addObjectPostProcessor(this.objectPostProcessor); // 注入 ObjectPostProcessor
configurer.setBuilder((B) this); // 设置 Builder 引用(双向关联)
add(configurer); // 加入内部列表
return configurer;
}
apply 方法做了三件关键的事:
addObjectPostProcessor:将 HttpSecurity 持有的ObjectPostProcessor注入到 Configurer 中。Configurer 在后续创建 Filter 时,需要用这个处理器确保 Filter 也受 Spring 容器管理。setBuilder((B) this):建立双向关联------Configurer 内部可以通过getBuilder()拿到 HttpSecurity,用于获取共享对象(如 AuthenticationManager)。add(configurer):将 Configurer 注册到内部的configurersMap 中。如果没有这一步,http.build()时这个 Configurer 就不会被遍历到,对应的 Filter 也不会被创建。
阶段三:add 方法------记录到 LinkedHashMap:
java
// AbstractConfiguredSecurityBuilder 内部
private final LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>,
List<SecurityConfigurer<O, B>>> configurers = new LinkedHashMap<>();
private <C extends SecurityConfigurer<O, B>> void add(C configurer) {
Assert.notNull(configurer, "configurer cannot be null");
Class<? extends SecurityConfigurer<O, B>> clazz =
(Class<? extends SecurityConfigurer<O, B>>) configurer.getClass();
synchronized (this.configurers) {
if (this.buildState.isConfigured()) {
throw new IllegalStateException(
"Cannot apply " + configurer + " to already built object");
}
// 从 Map 中取出该类型的列表(如果不存在则创建)
List<SecurityConfigurer<O, B>> configs =
this.configurers.getOrDefault(clazz, new ArrayList<>(1));
configs.add(configurer);
this.configurers.put(clazz, configs);
}
}
设计要点:
LinkedHashMap→ 保持 Configurer 的插入顺序- Key 是 Configurer 的 Class 类型 → 同类型的 Configurer 会被归入同一列表(
getOrApply负责去重) synchronized→ 线程安全,防止并发构建
1.4 with() 方法:apply() 的现代化替代
从 Spring Security 6.x 开始,推荐使用 with() 方法来注册自定义 Configurer:
java
public <C extends SecurityConfigurerAdapter<O, B>> B with(
C configurer, Customizer<C> customizer) throws Exception {
configurer.addObjectPostProcessor(this.objectPostProcessor);
configurer.setBuilder((B) this);
add(configurer); // 先注册
customizer.customize(configurer); // 后配置
return (B) this;
}
澄清 :在 Spring Security 6.4.x 中,
apply()方法本身并未 被标记为@Deprecated。被标记废弃的是各个无参配置方法(如csrf(),formLogin()等),推荐使用 Lambda DSL 替代。with()方法是新增的便捷 API,它将customizer.customize()放在add()之后执行------这意味着自定义配置一定是在 Configurer 已经完成注册和基础设置后才应用的,对于自定义 Configurer 的注册,apply()仍然可用且有效。
1.5 Configurer → Filter 映射表
| 你写的配置 | 对应的 Configurer | 最终产出的 Filter |
|---|---|---|
| http.formLogin() | FormLoginConfigurer | UsernamePasswordAuthenticationFilter |
| http.httpBasic() | HttpBasicConfigurer | BasicAuthenticationFilter |
| http.csrf() | CsrfConfigurer | CsrfFilter |
| http.cors() | CorsConfigurer | CorsFilter |
| http.authorizeHttpRequests() | AuthorizeHttpRequestsConfigurer | AuthorizationFilter |
| http.sessionManagement() | SessionManagementConfigurer | SessionManagementFilter |
| http.logout() | LogoutConfigurer | LogoutFilter |
| http.anonymous() | AnonymousConfigurer | AnonymousAuthenticationFilter |
| http.rememberMe() | RememberMeConfigurer | RememberMeAuthenticationFilter |
| http.headers() | HeadersConfigurer | HeaderWriterFilter |
| http.exceptionHandling() | ExceptionHandlingConfigurer | ExceptionTranslationFilter |
二、构建过程:doBuild 三步曲完整拆解
2.0 触发入口:SecurityBuilder.build()
一切始于 SecurityBuilder.build() 方法:
java
// SecurityBuilder 接口
public interface SecurityBuilder<O> {
O build() throws Exception;
}
// AbstractSecurityBuilder 抽象类
public abstract class AbstractSecurityBuilder<O> implements SecurityBuilder<O> {
private AtomicBoolean building = new AtomicBoolean();
private O object;
@Override
public final O build() throws Exception {
if (this.building.compareAndSet(false, true)) {
this.object = doBuild(); // ★ 委托给子类的 doBuild
return this.object;
}
throw new AlreadyBuiltException("This object has already been built");
}
protected abstract O doBuild() throws Exception;
}
关键设计:
AtomicBoolean保证同一个 Builder 只能被build()一次(防重复构建)- 模板方法模式:
build()是 final 的,子类只能实现doBuild()
2.1 doBuild 三步曲
AbstractConfiguredSecurityBuilder.doBuild 是三者的核心:
java
@Override
protected final O doBuild() throws Exception {
synchronized (this.configurers) {
this.buildState = BuildState.INITIALIZING;
beforeInit();
init(); // ★ 第一步:初始化
this.buildState = BuildState.CONFIGURING;
beforeConfigure();
configure(); // ★ 第二步:配置(创建 Filter)
this.buildState = BuildState.BUILDING;
O result = performBuild(); // ★ 第三步:构建(排序+组装)
this.buildState = BuildState.BUILT;
return result;
}
}
synchronized (this.configurers) --- 整个构建过程是同步的,因为 configurers 这个 LinkedHashMap 在 init/configure 阶段会被遍历和修改,必须保证线程安全。
2.2 第一步:init() ------ 初始化阶段
java
private void init() throws Exception {
Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
for (SecurityConfigurer<O, B> configurer : configurers) {
configurer.init((B) this);
}
}
init 阶段的具体任务(以几个典型 Configurer 为例):
| Configurer | init() 做了什么 |
|---|---|
| FormLoginConfigurer | 确认登录页面 URL、初始化认证相关的默认 Filter |
| CsrfConfigurer | 初始化 CSRF Token 仓库(默认 HttpSessionCsrfTokenRepository) |
| LogoutConfigurer | 初始化登出处理器、登出成功处理器 |
| SessionManagementConfigurer | 初始化会话认证策略(SessionAuthenticationStrategy) |
2.3 第二步:configure() ------ 创建 Filter 阶段(★ 最关键)
java
private void configure() throws Exception {
Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
for (SecurityConfigurer<O, B> configurer : configurers) {
configurer.configure((B) this);
}
}
这是整个构建过程中最关键的一步:每个 Configurer 在此创建自己负责的 Filter,并调用 http.addFilter(filter) 添加到 HttpSecurity 的过滤器列表。
完整实例一:CsrfConfigurer.configure()
以 CSRF 为例,看一个 Configurer 是如何变成 Filter 的:
java
// CsrfConfigurer 的 configure 方法
@Override
public void configure(H http) {
// ① 创建 CsrfFilter
CsrfFilter filter = new CsrfFilter(this.csrfTokenRepository);
// ② 设置需要 CSRF 保护的请求匹配器(默认匹配所有"危险"方法:POST/PUT/DELETE)
RequestMatcher requireCsrfProtectionMatcher = getRequireCsrfProtectionMatcher();
if (requireCsrfProtectionMatcher != null) {
filter.setRequireCsrfProtectionMatcher(requireCsrfProtectionMatcher);
}
// ③ 设置拒绝访问处理器(CSRF Token 不匹配时如何处理)
AccessDeniedHandler accessDeniedHandler = createAccessDeniedHandler(http);
if (accessDeniedHandler != null) {
filter.setAccessDeniedHandler(accessDeniedHandler);
}
// ④ 将 CSRF Token 清除处理器注册到登出流程
LogoutConfigurer<H> logoutConfigurer = http.getConfigurer(LogoutConfigurer.class);
if (logoutConfigurer != null) {
logoutConfigurer.addLogoutHandler(
new CsrfLogoutHandler(this.csrfTokenRepository));
}
// ⑤ 将 CSRF 会话认证策略注册到会话管理流程
SessionManagementConfigurer<H> sessionConfigurer =
http.getConfigurer(SessionManagementConfigurer.class);
if (sessionConfigurer != null) {
sessionConfigurer.addSessionAuthenticationStrategy(
getSessionAuthenticationStrategy());
}
// ⑥ 后置处理(如依赖注入)
filter = postProcess(filter);
// ⑦ 核心:将创建好的 CsrfFilter 添加到 HttpSecurity 的过滤器列表
http.addFilter(filter);
}
这个方法的精髓在于:它不仅创建了一个 CsrfFilter,还通过 http.getConfigurer() 拿到了其他 Configurer(如 LogoutConfigurer、SessionManagementConfigurer),并向它们注册了 CSRF 相关的处理器。Configurer 之间可以通过 HttpSecurity 这个"共享上下文"相互协作。
完整实例二:AuthorizeHttpRequestsConfigurer.configure()
java
@Override
public void configure(H http) {
// ① 从注册表创建授权管理器(合并所有 URL 映射规则)
AuthorizationManager<HttpServletRequest> authorizationManager =
this.registry.createAuthorizationManager();
// ② 创建 AuthorizationFilter
AuthorizationFilter authorizationFilter =
new AuthorizationFilter(authorizationManager);
// ③ 设置授权事件发布器
authorizationFilter.setAuthorizationEventPublisher(this.publisher);
// ④ 设置 SecurityContext 持有者策略
authorizationFilter.setSecurityContextHolderStrategy(
getSecurityContextHolderStrategy());
// ⑤ 添加到过滤器链
http.addFilter(postProcess(authorizationFilter));
}
2.4 第三步:performBuild() ------ 排序 + 组装
到了这一步,所有 Filter 都已经在 filters 列表中了。performBuild() 只需要做最后一件事------排序并包装:
java
// HttpSecurity.performBuild
@Override
protected DefaultSecurityFilterChain performBuild() {
// 校验:authorizeHttpRequests 和 authorizeRequests 不能同时使用
ExpressionUrlAuthorizationConfigurer<?> expressionConfigurer =
getConfigurer(ExpressionUrlAuthorizationConfigurer.class);
AuthorizeHttpRequestsConfigurer<?> httpConfigurer =
getConfigurer(AuthorizeHttpRequestsConfigurer.class);
boolean oneConfigurerPresent = expressionConfigurer == null ^ httpConfigurer == null;
Assert.state((expressionConfigurer == null && httpConfigurer == null) || oneConfigurerPresent,
"authorizeHttpRequests cannot be used in conjunction with authorizeRequests. Please select just one.");
// 排序:按照 FilterOrderRegistration 中定义的序号
this.filters.sort(OrderComparator.INSTANCE);
// 剥离 OrderedFilter 包装,只取裸 Filter
List<Filter> sortedFilters = new ArrayList<>(this.filters.size());
for (OrderedFilter orderedFilter : this.filters) {
sortedFilters.add(orderedFilter.filter);
}
// 构建并返回
return new DefaultSecurityFilterChain(this.requestMatcher, sortedFilters);
}
OrderComparator.INSTANCE是如何排序的? 由于OrderedFilter实现了Ordered接口,OrderComparator会直接调用其getOrder()方法获取顺序值,然后按升序排列。而这个顺序值,正是在 Filter 被http.addFilter()时,由FilterOrderRegistration中定义的序号注入的。
2.5 构建产物:DefaultSecurityFilterChain
java
public final class DefaultSecurityFilterChain implements SecurityFilterChain {
private final RequestMatcher requestMatcher; // 匹配哪些请求(例如 /api/**)
private final List<Filter> filters; // 已排序的过滤器列表
@Override
public boolean matches(HttpServletRequest request) {
return this.requestMatcher.matches(request);
}
@Override
public List<Filter> getFilters() {
return this.filters;
}
}
三、三个 performBuild 的完整实现对比
整个 Spring Security 的构建体系分为三层,每一层都有自己的 performBuild 实现。理解这三者的区别,是贯通整个框架架构的关键。
3.1 底层:AuthenticationManagerBuilder.performBuild()
java
@Override
protected ProviderManager performBuild() throws Exception {
if (!isConfigured()) {
return null; // 没有任何 AuthenticationProvider 配置
}
// ① 创建 ProviderManager,注入所有收集到的 AuthenticationProvider
ProviderManager providerManager = new ProviderManager(
this.authenticationProviders, // 所有注册的 Provider
this.parentAuthenticationManager // 父级认证管理器(可选)
);
// ② 设置配置
if (this.eraseCredentials != null) {
providerManager.setEraseCredentialsAfterAuthentication(this.eraseCredentials);
}
if (this.eventPublisher != null) {
providerManager.setAuthenticationEventPublisher(this.eventPublisher);
}
// ③ 后置处理
providerManager = postProcess(providerManager);
return providerManager;
}
- 产物 :
ProviderManager(包含一组AuthenticationProvider的责任链)
3.2 中间层:HttpSecurity.performBuild()
java
@Override
protected DefaultSecurityFilterChain performBuild() {
// ① 排序
this.filters.sort(OrderComparator.INSTANCE);
// ② 剥离包装
List<Filter> sortedFilters = new ArrayList<>(this.filters.size());
for (OrderedFilter orderedFilter : this.filters) {
sortedFilters.add(orderedFilter.filter);
}
// ③ 构建
return new DefaultSecurityFilterChain(this.requestMatcher, sortedFilters);
}
- 产物 :
DefaultSecurityFilterChain(一条规则 + 一组已排序的过滤器)
3.3 顶层:WebSecurity.performBuild()
WebSecurity 是 Spring Security 在 Servlet 容器中的总入口。它的 performBuild 是最终构建 FilterChainProxy 的地方------这是整个 Spring Security 的"最终产品"。
注意 :以下
springSecurityFilterChainBean 定义位于WebSecurityConfiguration类中,而非WebSecurity类中。WebSecurity.performBuild()是被该 Bean 定义调用的。
java
// WebSecurityConfiguration 中的 Bean 注册
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain(ObjectProvider<HttpSecurity> provider) throws Exception {
boolean hasFilterChain = !this.securityFilterChains.isEmpty();
// 如果用户没有定义任何 SecurityFilterChain,自动创建一个默认的
if (!hasFilterChain) {
this.webSecurity.addSecurityFilterChainBuilder(() -> {
HttpSecurity httpSecurity = provider.getObject();
httpSecurity.authorizeHttpRequests(authorize ->
authorize.anyRequest().authenticated());
httpSecurity.formLogin(Customizer.withDefaults());
httpSecurity.httpBasic(Customizer.withDefaults());
return httpSecurity.build();
});
}
// 注册用户自定义的 SecurityFilterChain
for (SecurityFilterChain securityFilterChain : this.securityFilterChains) {
this.webSecurity.addSecurityFilterChainBuilder(() -> securityFilterChain);
}
// 应用用户自定义的 WebSecurityCustomizer
for (WebSecurityCustomizer customizer : this.webSecurityCustomizers) {
customizer.customize(this.webSecurity);
}
// 最终构建 FilterChainProxy
return this.webSecurity.build();
}
// WebSecurity.performBuild
@Override
protected Filter performBuild() throws Exception {
// ① 收集所有 SecurityFilterChain
int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size();
List<SecurityFilterChain> securityFilterChains = new ArrayList<>(chainSize);
// 处理 ignored requests(已废弃,推荐用 permitAll)
for (RequestMatcher ignoredRequest : this.ignoredRequests) {
SecurityFilterChain securityFilterChain = new DefaultSecurityFilterChain(ignoredRequest);
securityFilterChains.add(securityFilterChain);
}
// 调用每个 SecurityBuilder.build() 构建 SecurityFilterChain
for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder :
this.securityFilterChainBuilders) {
SecurityFilterChain securityFilterChain = securityFilterChainBuilder.build();
securityFilterChains.add(securityFilterChain);
}
// ② 创建 FilterChainProxy
FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
// ③ 配置防火墙
if (this.httpFirewall != null) {
filterChainProxy.setFirewall(this.httpFirewall);
}
// ④ 配置请求拒绝处理器
if (this.requestRejectedHandler != null) {
filterChainProxy.setRequestRejectedHandler(this.requestRejectedHandler);
}
// ⑤ 后置处理
filterChainProxy.afterPropertiesSet();
// ⑥ 如果开启 debug,包装一层 DebugFilter
Filter result = filterChainProxy;
if (this.debugEnabled) {
result = new DebugFilter(filterChainProxy);
}
return result;
}
- 产物 :
FilterChainProxy(实现了jakarta.servlet.Filter接口,作为 Spring Security 在 Servlet 容器中的唯一代表)
3.4 三层体系的职责对照
| 层级 | 类 | 产物 | 一句话 |
|---|---|---|---|
| 底层 | AuthenticationManagerBuilder | ProviderManager | 构建认证核心------"谁能登录" |
| 中间层 | HttpSecurity | DefaultSecurityFilterChain | 构建安全规则------"这条链有什么规则" |
| 顶层 | WebSecurity | FilterChainProxy | 构建总代理------"所有链的统一入口" |
四、多过滤器链的路由机制(附完整示例)
一个应用可以配置多条 SecurityFilterChain,FilterChainProxy 会按 @Order 顺序逐一匹配:
java
@Bean
@Order(1) // ★ 优先级最高,先被检查
public SecurityFilterChain apiSecurityFilterChain(HttpSecurity http) throws Exception {
http
.securityMatcher("/api/**") // 匹配规则:/api/** 的请求走这条链
.csrf(csrf -> csrf.disable())
.sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.addFilterBefore(jwtFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated());
return http.build();
}
@Bean
@Order(2) // ★ 优先级次之,链1不匹配时才检查
public SecurityFilterChain webSecurityFilterChain(HttpSecurity http) throws Exception {
http
.securityMatcher("/**") // 兜底规则:匹配所有请求
.formLogin(form -> form.loginPage("/login"))
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated());
return http.build();
}
路由规则:
- 请求
/api/users→ 链1检查 →securityMatcher("/api/**")匹配 ✅ → JWT 认证 - 请求
/dashboard→ 链1检查 →securityMatcher("/api/**")不匹配 ❌ → 链2检查 →securityMatcher("/**")匹配 ✅ → 表单认证
@Order决定检查顺序,securityMatcher决定匹配条件;第一个匹配的链执行,后续链不再检查
⚠️ 注意 :@Order 和 securityMatcher 是两个独立的维度。@Order 决定哪条链先被检查,securityMatcher 决定该请求是否属于这条链。
五、完整构建流程图

六、总结
本文从顶层到底层完整拆解了 Spring Security 的构建体系。三个核心认知:
| 认知层次 | 核心知识点 | 一句话 |
|---|---|---|
| Builder 模式 | doBuild 三步曲 | init(初始化依赖)→ configure(创建 Filter)→ performBuild(排序组装) |
| Configurer 机制 | http.xxx() → Configurer → Filter | 每个安全功能的配置背后都有一个 Configurer,在 configure 阶段创建并注册 Filter |
| 三层构建体系 | AuthMgrBuilder → HttpSecurity → WebSecurity | 从认证核心到安全链再到总入口,层层递进 |
最重要的概念:getOrApply + apply + add + doBuild 是 Spring Security 配置体系的"骨架"。理解了这个机制:
- 你就知道为什么
http.formLogin()会生成UsernamePasswordAuthenticationFilter - 你就知道自定义过滤器为什么用
addFilterBefore而非直接addFilter - 你就知道为什么同一个 Configurer 只能配置一次(
getOrApply的去重逻辑)
| 串联知识点 | 说明 |
|---|---|
| HttpSecurity 创建 | HttpSecurityConfiguration,prototype 作用域,默认开启 10 个安全功能 + 条件加载 |
| Configurer 注册 | getOrApply → apply → add(去重 + ObjectPostProcessor注入 + 双向关联) |
| doBuild 三步曲 | init() → configure() → performBuild() |
| 三个 performBuild | ProviderManager / DefaultSecurityFilterChain / FilterChainProxy |
| FilterChainProxy | 总入口:多链路由 + 防火墙 + 虚拟链驱动 |
下一篇预告:将深入分析 Spring Security 的总入口 ------ FilterChainProxy.doFilter() 的完整实现------多链路由匹配(getFilters)、请求防火墙校验(HttpFirewall)、虚拟过滤器链驱动(VirtualFilterChain)、以及异常处理与 SecurityContext 清理的完整源码。