Spring Security架构总览与过滤器链详解
定位:第 01 篇,讲透 Spring Security 的职责定位、过滤器链架构、6.x 组件化配置模型与请求处理流程
适用版本:Spring Security 6.x(Spring Boot 3.x)
目录
一、Security 定位
1.1 两大职责
| 职责 | 问题 | 本篇/后续 |
|---|---|---|
| 认证(Authentication) | 你是谁 | 02 篇 |
| 授权(Authorization) | 你能做什么 | 03 篇 |
1.2 附加防护
框架同时内置常见 Web 攻击的默认防护:CSRF、会话固定攻击、点击劫持(安全响应头)、凭证在日志中的泄露防护等。默认开启、按需调整是其设计哲学------安全能力默认就位,而不是靠开发者记得去做。
1.3 在请求链路中的位置
请求 → Servlet 容器 → Security 过滤器链 → DispatcherServlet → 业务
Security 位于业务之前,所有请求先过安全链------这也是它能统一拦截鉴权的原因。
二、过滤器链架构
2.1 三层结构
DelegatingFilterProxy ← Servlet 层:把过滤器调用桥接给 Spring 容器
│
▼
FilterChainProxy ← Security 总调度:持有所有 SecurityFilterChain
│
▼
SecurityFilterChain ← 一组按序执行的过滤器
├── SecurityContextHolderFilter 建立/清理安全上下文
├── UsernamePasswordAuthenticationFilter 认证(表单登录)
├── CsrfFilter CSRF 防护
├── ExceptionTranslationFilter 安全异常转 401/403
└── AuthorizationFilter 最终授权判定
2.2 关键组件职责
| 组件 | 职责 |
|---|---|
DelegatingFilterProxy |
Servlet 规范过滤器,代理到 Spring 容器中的 Bean |
FilterChainProxy |
Security 的入口 Bean,管理多条链 |
SecurityFilterChain |
一条链 = 请求匹配器 + 有序过滤器集合 |
SecurityContextHolder |
线程级安全上下文(当前认证信息)的存取(02 篇展开) |
2.3 为什么用过滤器链实现
- 层次清晰:每个过滤器单一职责(认证、授权、防护分开),可增删替换;
- 可扩展:自定义过滤器插入链的任意位置;
- 统一入口:所有请求无差别经过,不存在遗漏的路径。
三、配置模型(6.x)
3.1 组件化配置(主流写法)
java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**", "/login").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated())
.formLogin(Customizer.withDefaults())
.csrf(csrf -> csrf.ignoringRequestMatchers("/api/**")); // 无状态 API 常关
return http.build();
}
}
要点:
- 每个 @Bean SecurityFilterChain 是一条链 ;6.x 移除了继承
WebSecurityConfigurerAdapter的旧写法; - 规则是声明式的:匹配器 + 访问要求;
- Lambda DSL 是 6.x 标准风格。
3.2 多链配置
多个 SecurityFilterChain Bean + @Order
请求按 order 从小到大找第一条【匹配】的链执行
典型:/api/** 一条无状态 JWT 链,其余走表单会话链------同一应用混合多种认证形态。
3.3 自定义过滤器插入
java
http.addFilterBefore(new JwtAuthFilter(), UsernamePasswordAuthenticationFilter.class);
自定义过滤器(如 JWT 解析)插到认证过滤器之前,把凭证解析结果放入安全上下文。
四、请求处理流程
① 请求到达 → DelegatingFilterProxy → FilterChainProxy
② 按 order + 请求匹配器选择 SecurityFilterChain
③ 依次执行链内过滤器:
安全上下文初始化 → 认证过滤器(解析/校验凭证)
→ ExceptionTranslationFilter(包裹后续,处理安全异常)
→ AuthorizationFilter(最终授权判定)
④ 全部通过 → 放行到 DispatcherServlet
认证失败 → 401(未认证);授权失败 → 403(无权限)
两个关键过滤器:
- ExceptionTranslationFilter :不干活,只负责把下游抛出的
AuthenticationException转认证入口(401/跳登录)、AccessDeniedException转 403------安全异常的统一翻译层; - AuthorizationFilter(6.x 取代 FilterSecurityInterceptor):链上最后的守门员,按规则判定放行/拒绝。
五、默认安全与放行
5.1 Boot 的默认行为
只引入 spring-boot-starter-security 不写配置:
所有路径需要认证
默认用户 user + 控制台打印的随机密码
表单登录 + HTTP Basic 都启用
默认拒绝(deny by default)------忘记配置也不会裸奔,这是正确的安全方向。
5.2 放行规则纪律
① 只放行明确公开的:登录页、健康检查、静态资源、公开接口
② 放行路径用明确匹配,避免 /** 误放
③ 管理端点(Actuator 敏感端点)单独保护
④ 新增接口默认走认证,显式放行需评审
六、总结
- 职责:认证 + 授权 + 常见攻击默认防护;位于业务之前的统一拦截层。
- 三层架构:DelegatingFilterProxy(桥接)→ FilterChainProxy(调度)→ SecurityFilterChain(有序过滤器);过滤器单一职责、可插拔。
- 6.x 配置:@Bean SecurityFilterChain + HttpSecurity Lambda DSL;多链按 @Order + 匹配器选择;自定义过滤器 addFilterBefore 插入。
- 处理流程:匹配链 → 依次过滤器 → ExceptionTranslationFilter 翻译异常 → AuthorizationFilter 终审;失败转 401/403。
- 默认拒绝:Boot 默认全路径认证;放行要显式、精确、可评审。
七、常见高频面试题
1. Spring Security 的核心职责是什么?
要点:两大核心------认证(Authentication,确认"你是谁")与授权(Authorization,判定"你能做什么");同时内置常见攻击防护:CSRF、会话固定、安全响应头(防点击劫持)等,默认开启。实现上是一条位于业务之前的过滤器链,所有请求统一经过,做到默认拒绝、安全能力集中管理。
2. 描述 Spring Security 过滤器链的结构。
要点:三层。DelegatingFilterProxy 是 Servlet 规范过滤器,把调用桥接给 Spring 容器;FilterChainProxy 是 Security 的入口,管理多条 SecurityFilterChain;每条链是有序过滤器集合,典型成员:SecurityContextHolderFilter(上下文)、各类认证过滤器(如 UsernamePasswordAuthenticationFilter)、CsrfFilter、ExceptionTranslationFilter(异常翻译)、AuthorizationFilter(最终授权)。请求按链顺序逐个过滤器执行。
3. Spring Security 6.x 怎么配置?和旧版本有什么区别?
要点:6.x 用组件化配置:@Bean SecurityFilterChain + HttpSecurity 的 Lambda DSL 声明规则;移除了继承 WebSecurityConfigurerAdapter 的旧写法(5.7 起弃用);配置从"继承重写方法"变为"声明 Bean",更符合 Spring 风格且支持多链。授权 API 也从 antMatchers/mvcMatchers 统一为 requestMatchers。理解"一切皆 Bean + 链"是掌握 6.x 的关键。
4. 多个 SecurityFilterChain 时,请求如何匹配?
要点:多个链 Bean 按 @Order 排序;请求到来时从小到大遍历,第一条请求匹配器(requestMatcher)命中的链负责处理,后续链不再执行。用于同一应用混合多种安全策略:如 /api/** 走无状态 JWT 链,管理后台走表单会话链。注意匹配顺序------范围宽的链放后面,避免先命中导致后面的链失效。
5. ExceptionTranslationFilter 的作用是什么?
要点:它是安全异常的翻译层,本身不做认证授权,而是包裹其后的过滤器:捕获下游抛出的 AuthenticationException(未认证)转成认证入口响应(返回 401 或重定向登录页),捕获 AccessDeniedException(无权限)转 403。它让"拒绝"有了统一的、对客户端友好的表达方式,并衔接登录/异常页配置。
6. 自定义过滤器怎么加进 Security 链?常见用途?
要点:用 HttpSecurity 的 addFilterBefore/addFilterAfter/addFilterAt,指定参照的内置过滤器位置。最常见用途:JWT 认证过滤器------插在 UsernamePasswordAuthenticationFilter 之前,解析请求头中的 Token、校验后把 Authentication 放入 SecurityContextHolder,使后续授权过滤器能识别身份。注意自定义过滤器要处理异常与上下文清理,避免污染后续请求。
7. SecurityContextHolder 是什么?
要点:存储当前线程安全上下文(SecurityContext,含 Authentication 认证信息)的持有者,默认 ThreadLocal 实现------链上任何位置都能取到当前用户。过滤器链在请求开始建立上下文、结束清理;异步场景默认不传播(需策略配置,如 MODE_INHERITABLETHREADLOCAL 或显式传递)。它是"当前登录用户"在代码中的来源。
8. 只引入 security starter 不写配置,会发生什么?
要点:Boot 安全自动配置生效:所有路径需要认证;默认用户名为 user,密码是启动时控制台打印的随机 UUID;表单登录与 HTTP Basic 都启用。这是"默认拒绝"设计------忘记配置不会裸奔。生产应显式配置规则与用户来源,而不是依赖随机密码。
9. 401 和 403 在 Security 里分别对应什么?
要点:401 未认证------请求没有有效身份凭证(AuthenticationException),响应应引导去认证(登录页/返回需要 Token);403 已认证但无权限(AccessDeniedException),说明身份有效但授权规则不允许。两者由 ExceptionTranslationFilter 区分产生。客户端处理逻辑不同:401 跳登录/刷新凭证,403 提示无权限。
10. 为什么说安全配置要"默认拒绝、显式放行"?
要点:默认拒绝(deny by default)保证未明确允许的路径一律需要认证------新增接口自动受保护,不会因遗漏配置而暴露;显式放行要求每个公开路径被明确声明与评审,减少"无意间公开了敏感接口"的风险。反模式是 permitAll 全放行后再打补丁式加保护。纪律:放行清单最小化、管理端点单独保护、放行变更需评审。
