Skip to content
概述
Spring Security 是 Spring 生态中负责应用安全的框架。在 Spring Boot 3 环境中,它基于 Servlet 安全链路工作,将认证、授权、上下文保存、异常处理和登录态恢复拆分为一组可组合的过滤器和策略对象。核心入口是 SecurityFilterChain,应用启动后由 FilterChainProxy 接管所有安全相关的请求过滤。
基本概念
- SecurityContextHolder —— 线程内安全上下文入口。认证成功后,
Authentication对象存放在此。 - Authentication —— 当前主体的抽象,包含身份(principal)、凭证(credentials)及权限(authorities)。
- UserDetailsService —— 账号读取入口。接受用户名,返回
UserDetails供AuthenticationManager校验。 - AuthenticationManager —— 认证调度器,通常委托给多个
AuthenticationProvider完成具体校验。 - AuthorizationManager —— 授权决策器(Spring Security 6 引入),替代旧版
AccessDecisionManager,支持基于请求和方法的授权。 - SecurityFilterChain —— 一条安全过滤器链,封装一组有序的安全过滤器,每条链对应一组匹配规则。
- FilterChainProxy —— 安全链总入口。根据请求路径选择命中的
SecurityFilterChain,并按顺序执行链上过滤器。
工作原理
请求进入容器后,经过以下阶段:
- Servlet Filter 阶段 —— 请求到达
DelegatingFilterProxy,该代理将过滤委托给 Spring 容器中的springSecurityFilterChain(即FilterChainProxy)。 - 链匹配 ——
FilterChainProxy内部维护多条SecurityFilterChain,每条链有自定义的RequestMatcher。按顺序匹配,命中后即使用该链的全部过滤器。 - 过滤器执行 —— 命中链上的过滤器按固定顺序执行:
SecurityContextPersistenceFilter(或SecurityContextHolderFilter)负责恢复或创建SecurityContext。UsernamePasswordAuthenticationFilter等认证过滤器处理登录请求。AuthorizationFilter检查当前主体是否满足授权规则。ExceptionTranslationFilter处理认证、授权过程中抛出的异常,并返回相应响应(如 401、403 或重定向到登录页)。
- 请求后清理 —— 请求结束后,
SecurityContextHolder中的上下文被清除,避免线程污染。
默认过滤器链顺序如下(开启 DEBUG 日志可观察):
DisableEncodeUrlFilter
WebAsyncManagerIntegrationFilter
SecurityContextHolderFilter
HeaderWriterFilter
CorsFilter
CsrfFilter
LogoutFilter
UsernamePasswordAuthenticationFilter
DefaultLoginPageGeneratingFilter
DefaultLogoutPageGeneratingFilter
BasicAuthenticationFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
ExceptionTranslationFilter
AuthorizationFilter这些过滤器的顺序由 FilterOrderRegistration 和各个过滤器内部定义的 order 决定。
基本用法
依赖与配置
Spring Boot 3 + Spring Security 6 的起步依赖:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>引入后,所有端点默认启用安全保护,并生成一个临时密码(印在启动日志中)。实际控制行为需要提供一个 SecurityFilterChain Bean:
java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/auth/**", "/public/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults());
return http.build();
}
}authorizeHttpRequests定义授权规则。formLogin()开启表单登录(包括自动生成登录页和认证流程)。permitAll()放行匹配的请求,无需认证。authenticated()要求所有其他请求必须已认证。
定义用户
可在内存中定义用户,或通过 UserDetailsService 从数据库加载。
java
@Bean
UserDetailsService userDetailsService() {
UserDetails user = User.builder()
.username("editor")
.password("{noop}secret") // 仅演示,实际部署应使用 {bcrypt} 等编码
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}Spring Security 6 要求密码编码格式为 {id}encodedPassword。{noop} 表示不加密(仅用于示例)。
获取当前用户
在控制器中可直接注入 Authentication 或 Principal:
java
@RestController
@RequestMapping("/api")
public class MeController {
@GetMapping("/me")
Map<String, Object> me(Authentication authentication) {
return Map.of(
"name", authentication.getName(),
"authorities", authentication.getAuthorities());
}
}API
以下列出配置安全行为时最常用的类型与方法。
| 类型 | 说明 |
|---|---|
HttpSecurity | 用于构建 SecurityFilterChain,提供 authorizeHttpRequests()、formLogin()、httpBasic()、csrf() 等配置入口。 |
SecurityFilterChain | 通过 HttpSecurity.build() 生成,代表一条完整的过滤器链。 |
UserDetailsService | 实现 loadUserByUsername(String) 返回 UserDetails,供认证管理器使用。 |
AuthenticationManager | 认证入口,通常通过注入 AuthenticationManagerBuilder 或覆写 authenticationManager Bean 来定制。 |
AuthorizationManager | Spring Security 6 新增的授权抽象,替代 AccessDecisionManager。 |
@EnableWebSecurity | 用在 @Configuration 类上,激活自定义配置,并暴露 SecurityFilterChain Bean。 |
@EnableMethodSecurity | 启用方法级安全(@PreAuthorize、@PostAuthorize 等),代替旧版 @EnableGlobalMethodSecurity。 |
HttpSecurity 常用方法:
java
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.defaultSuccessUrl("/home")
)
.httpBasic(Customizer.withDefaults())
.csrf(csrf -> csrf.disable());requestMatchers支持 Ant 模式、正则表达式及HttpMethod限定,按声明顺序依次匹配。formLogin()配置表单登录行为;httpBasic()开启 HTTP Basic 认证。csrf()用于控制跨站请求伪造保护。
示例
示例一:默认表单登录行为
应用启动后访问 http://localhost:8080/api/me(未授权),会被重定向到自动生成的登录页 http://localhost:8080/login。输入内存用户 editor / secret 后,重定向回 /api/me,返回 JSON:
json
{
"name": "editor",
"authorities": [{"authority": "ROLE_USER"}]
}开启调试日志 logging.level.org.springframework.security=DEBUG 时,控制台会输出类似下面的内容:
... DEBUG ... FilterChainProxy : Securing GET /api/me
... DEBUG ... FilterChainProxy : Triggering chain: [SecurityContextHolderFilter, ...]
... DEBUG ... AuthorizationFilter : Authorized filter invocation [GET /api/me] with attributes [authenticated]这表明 FilterChainProxy 完成了链的匹配与过滤器的逐层执行。
示例二:关闭 CSRF 保护并使用 HTTP Basic 测试
对于纯 API 服务,经常需要关闭 CSRF 保护:
java
http
.csrf().disable()
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/**").authenticated()
)
.httpBasic(Customizer.withDefaults());这时可用 HTTP Basic 认证访问。Node.js 客户端示例如下:
javascript
const url = 'http://localhost:8080/api/me';
const auth = Buffer.from('editor:secret').toString('base64');
fetch(url, {
headers: { 'Authorization': `Basic ${auth}` }
})
.then(res => res.json())
.then(data => console.log(data));执行后输出:
json
{ "name": "editor", "authorities": [{"authority": "ROLE_USER"}] }请求携带的 Authorization 头经过 BasicAuthenticationFilter 解析,并将认证信息存入 SecurityContextHolder,随后的 AuthorizationFilter 据此完成授权检查。
示例三:自定义登录页
关闭默认自动生成登录页,提供自定义页面:
java
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/login", "/css/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.defaultSuccessUrl("/home")
.permitAll()
);需要将 loginPage 指定的路径在 authorizeHttpRequests 中显式放行,否则会因请求被拦截而不断重定向到登录页自身,形成重定向循环。
注意点
- 密码编码格式:从 Spring Security 5 开始采用委托编码器,必须是
{id}密码格式,如{bcrypt}$2a$...。不指定编码则报错。 - CSRF 保护:默认开启,对修改请求(POST、PUT、DELETE 等)强制校验
XSRF-TOKEN。无浏览器场景可禁用,但应评估风险。 - 过滤器顺序:自定义过滤器可通过
addFilterBefore、addFilterAfter插入到指定位置。插入位置不当可能导致认证短路或授权失效。 - 方法安全:除请求级别授权外,还可在服务方法上使用
@PreAuthorize、@PostAuthorize进行细粒度控制。需在主类上添加@EnableMethodSecurity(Spring Security 6 推荐方式)。 - 请求匹配器:
requestMatchers支持 Ant 模式、正则表达式和HttpMethod限定。匹配顺序按声明顺序,靠前的规则优先命中。 - Spring Security 5 到 6 的变更:
WebSecurityConfigurerAdapter被弃用,改为组件化 Bean 声明;AuthorizationManager替代AccessDecisionManager;默认安全头更严格。升级项目时需要移除旧的适配器写法。
限制
- 有状态会话依赖:基于表单登录和 Session 的认证机制天然依赖服务端状态。在无状态微服务架构中,需要替换为 JWT 或 OAuth2 令牌认证,否则水平扩展会遇到 Session 同步问题。
- 请求级授权能力:
authorizeHttpRequests只能基于请求路径和 HTTP 方法授权。对复杂业务权限(如“本人才能编辑自己的文章”)需结合方法安全注解或自定义AuthorizationManager。 - 默认配置的覆盖范围:自动配置只提供基础安全功能,对接第三方认证(OAuth2、SAML)时需要额外引入 starter 并调整配置。
- 性能考量:默认过滤器链较长,每条请求都会经过所有已添加的过滤器。高并发场景下若不需要某些功能(如 CSRF、Session 并发控制),显式关闭可减少开销。
应用
- 单体应用的登录、角色授权、页面保护。
- 前后端分离项目的 REST API 安全,常用 HTTP Basic、JWT 或 OAuth2。
- 与 Spring Cloud Gateway 配合,构建网关层统一认证。
- 方法级权限控制,用于服务层细粒度授权。
