Spring Security
Spring Security 是一个功能强大且易于使用的框架,能够帮助开发者提高应用程序的安全性和可靠性。无论是简单的身份验证需求,还是复杂的安全策略,Spring Security 都能提供相应的解决方案。
使用 spring boot 版本
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>3.5.6</version>
</parent>
Spring Security 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Spring Security 过滤链架构

DelegatingFilterProxy(代理过滤器)
Servlet 容器(如 Tomcat)自身的过滤器(Filter)是由容器直接创建和管理的,而 Spring 应用中的大部分组件(如 Service、Bean 等)是由 Spring 容器管理的。如果我们想让过滤器使用 Spring 容器中的 Bean(例如依赖注入 UserDetailsService 进行认证),直接注册原生 Filter 会面临一个问题:
Servlet 容器无法直接访问 Spring 容器中的 Bean,因为两者的生命周期和管理机制完全独立
DelegatingFilterProxy 正是为了解决这个问题而设计的 ,它作为 Servlet 容器和 Spring 容器之间的 “桥梁”,让过滤器的实际逻辑由 Spring 容器中的 Bean 来实现
DelegatingFilterProxy 本身并不处理具体的过滤逻辑,而是委托给 Spring 容器中一个真正的过滤器 Bean 来执行
FilterChainProxy(安全过滤链的总调度器)
FilterChainProxy 本身是一个由 Spring 容器管理的 Filter 实现类,但它不直接处理安全逻辑,而是管理多个 “安全过滤器链”(SecurityFilterChain),并根据请求的特征(如路径)匹配对应的链,再按顺序执行链中的过滤器。
springSecurityFilterChain (Bean名)

springSecurityFilterChain 是一个特殊的 Bean 名称,它指向的是 FilterChainProxy 类型的实例(即 Spring Security 核心的过滤链调度器)
FilterChainProxy 与SecurityFilterChain的关系:
FilterChainProxy 是 “总调度器”,内部维护一个 List<SecurityFilterChain>;
当请求到达时,FilterChainProxy 遍历所有 SecurityFilterChain,通过 matches 方法找到第一个匹配的链;
然后执行该链中 getFilters() 返回的过滤器(按顺序执行)。
补充:
可以配置多个SecurityFilterChain,官方文档

SecurityFilterChain(“请求范围 + 过滤器集合” 的基本单元)
SecurityFilterChain 是 Spring Security 中定义 “一组安全过滤器及其适用范围” 的核心接口,它是 FilterChainProxy 管理的最小单元,用于描述 “哪些请求需要经过哪些安全过滤器”。
public interface SecurityFilterChain {
// 判断当前请求是否匹配该过滤器链
boolean matches(HttpServletRequest request);
// 返回该链中包含的所有安全过滤器(按执行顺序排列)
List<Filter> getFilters();
}
默认过滤链
如果不配置 Spring Security,只要引入了 Spring Security 依赖就会创建16个默认过滤链,如下:

在 Spring Security 过滤器链中,会按顺序执行以上过滤链条。如果客户端发出一个请求,就会按顺序经过这些过滤链,顺利通过则到达控制层返回结果。有两种情况会中断过滤链:1.抛异常会中断 2.主动不调用下一个过滤器,中断后就不会到达控制层就不会返回结果,而是异常处理器捕获异常,给客户端返回异常信息,比如密码错误等信息
认证流程图
以UsernamePasswordAuthenticationFilter情况举例:

鉴权流程图
这两个代码是等价的

以上配置了会按下面的方式进行鉴权

核心接口与类
认证接口
AuthenticationManager
AuthenticationManager 是 Spring Security 中负责认证逻辑核心决策的接口,它是认证过程的 “入口点”,主要作用是接收认证请求(Authentication 对象),并返回认证成功的结果或抛出认证失败的异常。
@FunctionalInterface
public interface AuthenticationManager
{
//唯一的方法,承担认证的核心逻辑,参数和返回值均为 Authentication 类型,这是 Spring Security 中表示 “认证信息” 的核心类。
Authentication authenticate(Authentication authentication) throws AuthenticationException;
}
运行步骤:
- 接收一个未认证的 Authentication 对象(包含用户提交的凭据,如用户名、密码、令牌等);
- 执行认证逻辑(如调用 UserDetailsService 加载用户信息、比对密码、验证令牌有效性等);
- 认证成功:返回一个已认证的 Authentication 对象(包含用户身份、权限等信息);
认证失败:抛出 AuthenticationException 异常(如 BadCredentialsException 密码错误、UsernameNotFoundException 用户不存在等)。
使用方法:
若后续需要开发自定义登录接口(如前后端分离场景的 JSON 登录)
// 显式暴露 AuthenticationManager 为 Spring Bean,供应用中其他组件(如控制器、服务)注入使用
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
// AuthenticationConfiguration 是 Spring Security 自动配置的核心类,负责构建 AuthenticationManager
// 通过 getAuthenticationManager() 方法获取其自动配置的实例,该实例已整合:
// 1. 本类中定义的 UserDetailsService(此处为基于内存的用户服务)
// 2. 密码编码器(当前示例使用 {noop} 表示不加密,生产环境需配置 PasswordEncoder)
// 3. 认证提供者(默认使用 DaoAuthenticationProvider,通过 UserDetailsService 加载用户信息)
return authenticationConfiguration.getAuthenticationManager();
}
可注入此 AuthenticationManager 手动触发认证:
@Autowired
private AuthenticationManager authenticationManager;
// 自定义登录接口
@PostMapping("/api/login")
public String customLogin(@RequestBody LoginRequest request) {
// 构建认证请求对象
UsernamePasswordAuthenticationToken authRequest =
new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword());
// 调用 AuthenticationManager 执行认证
Authentication authentication = authenticationManager.authenticate(authRequest);
// 将认证结果存入 SecurityContext
SecurityContextHolder.getContext().setAuthentication(authentication);
return "登录成功";
}
AuthenticationProvider
AuthenticationProvider 是 Spring Security 中负责执行具体认证逻辑的核心接口,它是认证流程的 “实际执行者”,与 AuthenticationManager、UserDetailsService 等组件紧密配合,完成用户名密码校验、令牌验证等具体认证操作
public interface AuthenticationProvider {
/**
* 执行具体的认证逻辑
* @param authentication 待认证的信息(如用户名密码、令牌等)
* @return 已认证的 Authentication 对象(包含权限等信息)
* @throws AuthenticationException 认证失败时抛出
*/
Authentication authenticate(Authentication authentication) throws AuthenticationException;
/**
* 判断当前 Provider 是否支持某种 Authentication 类型
* @param authentication 待认证的类型
* @return true 表示支持,会调用上面的 authenticate 方法
*/
boolean supports(Class<?> authentication);
}
核心过程:
- 接收未认证的 Authentication 对象(如 UsernamePasswordAuthenticationToken 包含的用户名密码)。
- 执行具体认证逻辑(如校验密码、验证令牌签名、检查用户状态等)。
- 认证成功则返回已认证的 Authentication 对象(填充权限、用户信息等);失败则抛出 AuthenticationException(如密码错误、用户锁定)。
Authentication
Authentication 接口是 Spring Security 认证流程的 “数据载体”,贯穿整个认证过程:
- 认证前:通常由用户输入构建(如 UsernamePasswordAuthenticationToken 实现类,包含用户名 principal 和密码 credentials,authorities 为空,isAuthenticated 为 false)。
- 认证中:AuthenticationManager 接收该对象,执行验证逻辑。
- 认证后:验证通过后,principal 可能更新为完整用户对象,authorities 填充实际权限,credentials 可能被清空,isAuthenticated 设为 true。
public interface Authentication extends Principal, Serializable {
// 获取当前用户拥有的权限集合,例如 "ROLE_USER"、"ROLE_ADMIN" 或具体操作权限 "user:read"
Collection<? extends GrantedAuthority> getAuthorities();
// 凭证(如用户输入的原始密码 ,String 类型的密码、JWT 令牌等)认证成功后,为了安全起见,该信息可能会被清空(例如密码验证通过后不再保留)
Object getCredentials();
// 额外信息(如请求 IP、会话 ID)通常是用户名(String 类型)或用户实体对象(如自定义的 User 类),认证成功后,该信息会被保留用于标识当前用户。
Object getDetails();
// 身份标识(未认证时可能是用户名,认证后通常是 UserDetails)
Object getPrincipal();
// 是否已认证
boolean isAuthenticated();
// 设置认证状态
void setAuthenticated(boolean isAuthenticated);
}
UserDetails
用于封装从数据源(如数据库、缓存)加载的用户静态信息,是系统中 “用户数据” 的标准化表示。
public interface UserDetails extends Serializable {
String getUsername(); // 用户名
String getPassword(); // 加密后的密码
Collection<? extends GrantedAuthority> getAuthorities(); // 权限列表
boolean isAccountNonExpired(); // 账号是否未过期
boolean isAccountNonLocked(); // 账号是否未锁定
boolean isCredentialsNonExpired(); // 密码是否未过期
boolean isEnabled(); // 账号是否启用
}
UserDetailsService
UserDetailsService 是负责加载用户信息的核心接口,是认证流程中连接 “用户数据源” 与 “认证逻辑” 的关键桥梁。它的主要作用是根据用户名从数据源(如数据库、缓存、LDAP 等)中查询用户的详细信息(用户名、密码、权限、账号状态等),为认证提供必要的用户数据。
/**
* Spring Security核心接口:用于加载用户特定数据的策略接口
* 作为用户数据访问对象(DAO)的抽象,被{@link org.springframework.security.authentication.dao.DaoAuthenticationProvider}等认证提供者使用
* 实现类需提供根据用户名查询用户完整信息的逻辑(如从数据库、缓存或其他数据源获取)
*/
public interface UserDetailsService {
/**
* 根据用户名定位用户并加载其详细信息
* 实际实现中,用户名搜索可能区分大小写或不区分大小写,具体取决于实现类的配置
* 返回的UserDetails对象中的用户名可能与请求的用户名大小写不同(如数据库存储为大写,请求为小写)
*
* @param username 用于标识所需用户数据的用户名(不能为空)
* @return 完全填充的用户记录(必须非null,需包含用户名、密码、权限等认证所需信息,如您项目中的{@link org.example.pojo.CustomUser})
* @throws UsernameNotFoundException 如果用户不存在,或用户没有任何权限
*/
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
SecurityContextHolder(不是接口)
SecurityContextHolder 是 Spring Security 中用于存储和访问当前用户认证信息(SecurityContext) 的核心工具类,它提供了线程安全的方式来管理用户的安全上下文,是连接认证流程与后续权限校验的关键组件
核心方法
| 方法 | 说明 |
|---|---|
| getContext() | 获取当前线程绑定的 SecurityContext 对象(包含当前用户的 Authentication) |
| setContext(SecurityContext context) | 为当前线程设置 SecurityContext(通常由 Spring Security 内部调用,如认证成功后) |
| clearContext() | 清除当前线程的 SecurityContext(如用户登出时) |
| getContextHolderStrategy() | 获取当前使用的 SecurityContext 存储策略(默认是线程绑定) |
补充:
SecurityContextHolder → 持有 SecurityContext → 持有 Authentication(用户认证信息)。
授权接口
AuthorizationManager
在 Spring Security 6 中,AuthorizationManager 是用于权限校验的核心接口,它替代了 Spring Security 5 及之前版本中的 AccessDecisionManager,负责判断当前用户是否有权限访问特定资源(如请求、方法、URL 等)和AccessDecisionVoter
// 授权管理器接口:判断当前登录用户(Authentication)是否有权访问某个资源(如接口、页面)
@FunctionalInterface
public interface AuthorizationManager<T> {
/**
* 验证权限:无权限时直接抛异常
* @param authentication 提供当前用户认证信息的对象(含用户身份、权限)
* @param object 要访问的资源(如HttpServletRequest、接口路径等)
*/
default void verify(Supplier<Authentication> authentication, T object) {
// 先调用check方法判断权限,得到决策结果
AuthorizationDecision decision = check(authentication, object);
// 若决策结果存在且为“拒绝访问”,抛出授权失败异常
if (decision != null && !decision.isGranted()) {
throw new AuthorizationDeniedException("Access Denied", decision);
}
}
/**
* (已过时)检查权限:返回决策结果(允许/拒绝),不抛异常
* @param authentication 提供当前用户认证信息的对象
* @param object 要访问的资源
* @return 授权决策结果,null表示未做判断
*/
@Nullable
@Deprecated
AuthorizationDecision check(Supplier<Authentication> authentication, T object);
/**
* 检查权限(替代过时的check方法):返回决策结果,不抛异常
* @param authentication 提供当前用户认证信息的对象
* @param object 要访问的资源
* @return 授权决策结果,null表示未做判断
*/
@Nullable
default AuthorizationResult authorize(Supplier<Authentication> authentication, T object) {
// 默认调用旧的check方法,实现权限检查逻辑
return check(authentication, object);
}
}
自定义 AuthorizationManager
// 自定义授权管理器:仅允许特定用户访问
public class CustomAuthorizationManager implements AuthorizationManager<HttpServletRequest> {
@Override
AuthorizationResult authorize(Supplier<Authentication> authentication, T object)
{
Authentication auth = authentication.get();
if (auth == null) {
// 未认证,拒绝访问
return new AuthorizationDecision(false);
}
// 仅允许用户名包含 "admin" 的用户访问
String username = auth.getName();
boolean authorized = username.contains("admin");
return new AuthorizationDecision(authorized);
}
}
// 在 Security 配置中使用
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
// 对 /custom/** 路径应用自定义授权管理器
.requestMatchers("/custom/**").access(new CustomAuthorizationManager())
.anyRequest().authenticated()
);
return http.build();
}
AuthorizationResult
AuthorizationResult 是 Spring Security 权限校验的 “结果载体”
/**
* Spring Security 中表示权限校验结果的接口,用于封装"是否允许访问目标资源"的决策结果。
* 它是权限校验流程的最终输出,由 {@link AuthorizationManager} 生成并返回。
*/
public interface AuthorizationResult extends Serializable {
/**
* 判断当前权限校验是否允许访问目标资源。
*
* @return true 表示允许访问(权限校验通过),false 表示拒绝访问(权限校验失败)
*/
boolean isGranted();
}
RequestAuthorizationContext(不是接口)
RequestAuthorizationContext 封装 HTTP 请求相关信息的类,主要用于授权阶段,帮助 AuthorizationManager(授权管理器)判断 “当前请求是否有权访问目标资源”
AuthorizationManager<T> 的泛型T一般是RequestAuthorizationContext对象
// 封装 请求授权上下文:封装HTTP请求及路径变量信息,供授权判断使用
public final class RequestAuthorizationContext {
// HTTP请求对象(包含请求路径、方法、参数等信息)
private final HttpServletRequest request;
// 路径变量映射(如URL中{id}这类变量的键值对)
private final Map<String, String> variables;
/**
* 创建实例
* @param request HTTP请求对象
*/
public RequestAuthorizationContext(HttpServletRequest request) {
this(request, Collections.emptyMap());
}
/**
* 创建实例
* @param request HTTP请求对象
* @param variables 路径变量键值对(如从"/user/{id}"中提取的id值)
*/
public RequestAuthorizationContext(HttpServletRequest request, Map<String, String> variables) {
this.request = request;
this.variables = variables;
}
/**
* 获取HTTP请求对象
* @return 包含请求详情的HttpServletRequest
*/
public HttpServletRequest getRequest() {
return this.request;
}
/**
* 获取路径变量
* @return 路径中变量名与值的映射(如{id: "123"})
*/
public Map<String, String> getVariables() {
return this.variables;
}
}
认证类
ProviderManager(核心认证类)
ProviderManager 是 Spring Security 中 AuthenticationManager 接口的默认实现类,负责协调多个 AuthenticationProvider(认证提供者)完成认证流程,是认证逻辑的 “调度中心”。它解决了 “多种认证方式共存” 的问题(如用户名密码认证、OAuth2 认证、LDAP 认证等),通过委托不同的 AuthenticationProvider 处理对应类型的认证请求。
核心作用
接收认证请求(Authentication 对象),遍历其管理的 AuthenticationProvider 列表,找到能处理该请求的提供者并委托其执行认证,最终返回认证结果(已认证的 Authentication 或抛出异常)。
内部结构
ProviderManager 内部维护两个关键属性:
List:管理的认证提供者列表(如 DaoAuthenticationProvider 处理用户名密码认证,JwtAuthenticationProvider 处理 JWT 令牌认证)。
AuthenticationManager parent:父认证管理器(可选),当自身所有 AuthenticationProvider 都无法处理请求时,会委托父管理器处理(形成认证链)。
认证流程
当调用 ProviderManager.authenticate(Authentication) 方法时,流程如下:
遍历认证提供者:依次检查 List 中的每个提供者,通过 supports(Class<?>) 方法判断其是否能处理当前 Authentication 类型(如 UsernamePasswordAuthenticationToken 由 DaoAuthenticationProvider 处理)。
委托认证:找到第一个支持该认证类型的 AuthenticationProvider,调用其 authenticate(…) 方法执行具体认证逻辑。
处理结果:
若认证成功,返回已认证的 Authentication 对象(isAuthenticated() == true)。
若认证失败,抛出 AuthenticationException(如密码错误抛出 BadCredentialsException)。
若所有提供者都不支持当前认证类型,且存在父管理器(parent),则委托父管理器处理;若没有父管理器,抛出 ProviderNotFoundException。
DaoAuthenticationProvider
DaoAuthenticationProvider 是 Spring Security 中用于处理用户名密码认证的核心 AuthenticationProvider 实现类,是大多数基于账号密码登录场景的默认认证提供者。它通过整合 UserDetailsService(加载用户信息)和 PasswordEncoder(密码加密与校验),完成从 “接收用户输入” 到 “验证身份合法性” 的完整流程。
核心依赖
DaoAuthenticationProvider 的工作依赖两个关键组件:
UserDetailsService:负责根据用户名从数据源(如数据库、缓存)加载用户信息(UserDetails),包含加密后的密码、权限列表、账号状态(是否锁定、过期等)。
PasswordEncoder:负责密码的加密与校验(如 BCrypt、Argon2 等算法)。用户输入的原始密码会通过它与 UserDetails 中存储的加密密码进行比对。
认证流程
DaoAuthenticationProvider 的 authenticate 方法执行流程如下:
-
接收认证请求:接收未认证的 UsernamePasswordAuthenticationToken(包含用户输入的用户名和原始密码)。
-
加载用户信息:调用 UserDetailsService.loadUserByUsername(username) 获取 UserDetails 对象。若用户名不存在,抛出 UsernameNotFoundException。
-
校验账号状态:检查 UserDetails 中的账号状态(isAccountNonLocked()、isEnabled() 等),若账号锁定、过期或禁用,抛出对应异常(如 LockedException)。
-
校验密码:通过 PasswordEncoder.matches(rawPassword, encodedPassword) 比对用户输入的原始密码与 UserDetails 中存储的加密密码。若不匹配,抛出 BadCredentialsException(密码错误)。
-
生成认证结果:若上述校验均通过,调用 createSuccessAuthentication 方法生成已认证的 UsernamePasswordAuthenticationToken(包含用户信息、权限,isAuthenticated() 设为 true)并返回。
UsernamePasswordAuthenticationToken
UsernamePasswordAuthenticationToken 是 Spring Security 中用于封装用户名密码认证信息的核心 Authentication 实现类,贯穿于整个用户名密码认证流程,既是 “认证请求的载体”,也是 “认证成功后的凭证”。
核心作用
UsernamePasswordAuthenticationToken 的核心职责是:
认证前:封装用户输入的用户名和原始密码,作为向 AuthenticationManager 发起认证请求的 “未认证令牌”。
认证后:在认证成功后,被填充用户详细信息(UserDetails)和权限列表,作为 “已认证令牌” 存储在 SecurityContext 中,代表用户的身份凭证。
授权类
AuthorizationFilter(权限校验的核心过滤器)
AuthorizationFilter 是 Spring Security 中负责执行权限校验的核心过滤器,它在请求处理流程中拦截请求,调用 AuthorizationManager 进行权限判断,并根据结果决定是否允许请求继续处理(或拒绝访问)。它是 Spring Security 权限控制流程中连接 “请求拦截” 与 “权限决策” 的关键组件
校验核心代码
try {
AuthorizationResult result = this.authorizationManager.authorize(this::getAuthentication, request);
this.eventPublisher.publishAuthorizationEvent(this::getAuthentication, request, result);
if (result != null && !result.isGranted()) {
throw new AuthorizationDeniedException("Access Denied", result);
}
chain.doFilter(request, response);
} finally {
request.removeAttribute(alreadyFilteredAttributeName);
}
AuthorizationFilter 是 Spring Security 6 授权流程的核心过滤器,通过委托 AuthorizationManager 实现请求的权限校验。它简化了授权流程的设计,强化了 AuthorizationManager 的作用,使开发者能更灵活地配置不同资源的授权规则(如路径匹配、角色校验、认证状态判断等)。在实际开发中,通常无需直接操作 AuthorizationFilter,只需通过 authorizeHttpRequests 配置授权规则即可,其底层会自动完成与 AuthorizationFilter 的关联。
RequestMatcherDelegatingAuthorizationManager
RequestMatcherDelegatingAuthorizationManager 是 Spring Security 中用于基于请求路径(或请求特征)动态匹配授权规则的核心 AuthorizationManager 实现类。它允许为不同的请求路径、HTTP 方法等配置不同的授权策略,是实现 “细粒度 URL 权限控制” 的关键组件。
内部结构:
RequestMatcher 与 AuthorizationManager 的映射
它内部维护一个 Map<RequestMatcher, AuthorizationManager>,其中:
RequestMatcher:用于匹配请求(如通过 AntPathRequestMatcher 匹配 /admin/** 路径,或 MvcRequestMatcher 匹配 Spring MVC 路由)。
AuthorizationManager:对应请求的授权规则(如 AuthenticatedAuthorizationManager 要求 “已认证”,AuthorityAuthorizationManager 要求特定角色)。
工作流程:
当处理请求时,RequestMatcherDelegatingAuthorizationManager 按以下步骤执行:
-
匹配请求:遍历内部的 RequestMatcher 列表,找到第一个与当前请求匹配的 RequestMatcher。
-
委托授权:调用该 RequestMatcher 对应的 AuthorizationManager 的 check 方法,执行具体授权判断。
-
返回结果:将子授权器的判断结果(AuthorizationDecision)作为自身结果返回。
-
若没有匹配的 RequestMatcher,则使用默认授权器(默认拒绝访问,可自定义)。
AuthenticatedAuthorizationManager
AuthenticatedAuthorizationManager 是 Spring Security 中一个基础且常用的 AuthorizationManager 实现类,其核心功能是判断当前用户是否已完成认证(即是否已登录),是实现 “登录即可访问” 这类授权逻辑的关键组件。
工作流程:
AuthenticatedAuthorizationManager 通常作为 RequestMatcherDelegatingAuthorizationManager 的子授权器工作,完整流程如下:
- 请求到达 AuthorizationFilter(Spring Security 6 的授权过滤器)。
- AuthorizationFilter 调用顶层的 RequestMatcherDelegatingAuthorizationManager。
- 若请求匹配到 /user/** 等配置了 .authenticated() 的路径,RequestMatcherDelegatingAuthorizationManager 会委托 AuthenticatedAuthorizationManager 执行判断。
- AuthenticatedAuthorizationManager 检查用户是否已认证,返回授权结果。
- AuthorizationFilter 根据结果决定放行或拒绝访问。
RequestMatcherDelegatingAuthorizationManager 和 AuthenticatedAuthorizationManager关系
RequestMatcherDelegatingAuthorizationManager 和 AuthenticatedAuthorizationManager 最终由 FilterSecurityInterceptor 调用:
- FilterSecurityInterceptor 作为授权流程的入口,触发顶层的 RequestMatcherDelegatingAuthorizationManager。
- 后者根据请求路径分发到具体的子授权器(如 AuthenticatedAuthorizationManager)完成判断。
- 这种设计确保了所有请求在访问资源前都经过统一的授权校验,是 Spring Security 权限控制的核心机制
Spring Security配置
@Configuration // 标记为配置类,让 Spring 解析
@EnableWebSecurity // 启用 Spring Security 的 Web 安全支持
public class SecurityConfig {
@Bean
// 配置 SecurityFilterChain,定义安全拦截规则
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception
{
return http.build();
}
}
HttpSecurity 配置方法
| 方法名 | 作用 |
|---|---|
| authorizeHttpRequests() | 配置 HTTP 请求的授权规则(访问控制) |
| build() | 构建 SecurityFilterChain,完成配置 |
| authenticationProvider() | 注册自定义 AuthenticationProvider(执行认证逻辑) |
| authenticationManager() | 指定全局 AuthenticationManager(认证入口,协调多个 Provider) |
| userDetailsService() | 配置 UserDetailsService(加载用户信息供认证使用) |
| formLogin() | 配置基于表单的登录(自定义登录页、接口、成功 / 失败处理) |
| httpBasic() | 配置 HTTP 基本认证(浏览器原生登录框) |
| logout() | 配置用户注销行为(注销 URL、成功跳转、会话清理) |
| csrf() | 配置跨站请求伪造防护(开启 / 关闭、自定义令牌存储) |
| cors() | 配置跨域资源共享(允许指定域名、方法、请求头跨域) |
| sessionManagement() | 配置会话行为(创建策略、并发控制、超时处理) |
| rememberMe() | 配置 “记住我” 功能(令牌有效期、参数名、用户服务) |
| headers() | 配置 HTTP 安全响应头(防御 XSS、点击劫持等) |
| addFilterBefore() | 在指定过滤器之前添加自定义过滤器 |
| addFilterAfter() | 在指定过滤器之后添加自定义过滤器 |
| addFilterAt() | 在指定过滤器位置添加自定义过滤器(替代或并行执行) |
| exceptionHandling() | 配置认证 / 授权失败的处理逻辑(跳转页面、返回 JSON) |
| anonymous() | 配置匿名用户的身份(用户名、角色) |
| oauth2Login() | 配置 OAuth2/OpenID Connect 第三方登录(如社交登录) |
| oauth2ResourceServer() | 配置 OAuth2 资源服务器(验证 JWT 等令牌) |
| requiresChannel() | 强制 HTTP/HTTPS 切换(如敏感接口需 HTTPS) |
| objectPostProcessor() | 注册 ObjectPostProcessor,增强内部组件(如过滤器、Provider) |
authorizeHttpRequests
requestMatchers方法定义当前请求URI范围
常用访问控制规则:
| 方法 | 作用 |
|---|---|
| .permitAll() | 允许所有用户访问(包括匿名用户) |
| .denyAll() | 拒绝所有用户访问 |
| .authenticated() | 必须已认证(登录)才能访问 |
| .anonymous() | 仅允许匿名用户访问 |
| .hasRole(“角色”) | 需拥有指定角色(自动拼接 ROLE_ 前缀) |
| .hasAnyRole(“角色1”, “角色2”) | 拥有任一指定角色即可 |
| .hasAuthority(“权限”) | 需拥有指定权限(不拼接前缀 |
| .hasAnyAuthority(“权限1”, “权限2”) | 拥有任一指定权限即可 |
| .access(授权表达式) | 自定义复杂授权逻辑 |
objectPostProcessor(不替换组件修改属性)
老版本方法:withObjectPostProcessor
在 Spring Security 中,HttpSecurity 的 objectPostProcessor方法是一个强大的扩展点,用于在 Spring Security 内部组件(如过滤器、认证管理器等)初始化后,对其进行自定义加工。它基于 ObjectPostProcessor 接口工作,允许你在不替换组件的前提下,修改其属性、添加监听器或增强功能。
例子:
如果我想使用默认的配置,但是我想改一些参数,不需要大量修改,可以使用objectPostProcessor方法进行修改,将原来的参数username改为name
http.objectPostProcessor(new ObjectPostProcessor<Object>() {
@Override
public <O extends Object> O postProcess(O object) {
if (object instanceof UsernamePasswordAuthenticationFilter) {
((UsernamePasswordAuthenticationFilter)object).setUsernameParameter("name");
}
return object;
}
})
.formLogin();

补充:
配置顺序:HttpSecurity 的方法调用顺序决定了内部组件的创建和初始化顺序。将 .objectPostProcessor() 放在 .formLogin() 之前,可确保后处理器在 UsernamePasswordAuthenticationFilter创建时已注册,从而拦截并修改参数username
Spring Security 上下文
Spring Security 的上下文(SecurityContext)是框架中用于存储当前用户认证信息的核心组件,它贯穿整个请求生命周期,是实现用户身份识别、权限控制的基础。
- SecurityContext:存储当前用户的认证状态(Authentication 对象),包含用户身份、权限等关键信息。
- SecurityContextHolder:全局访问 SecurityContext 的工具类,通过它可以在应用任意位置获取当前上下文(无需手动传递认证信息)。
自定义过滤链
AbstractAuthenticationProcessingFilter
AbstractAuthenticationProcessingFilter 是 Spring Security 中处理认证请求的抽象基类,所有基于 HTTP 请求的认证过滤器(如处理用户名密码的 UsernamePasswordAuthenticationFilter、处理 JWT 的自定义过滤器等)都继承自它。它封装了认证流程的通用逻辑(如请求匹配、认证委托、成功 / 失败处理等),子类只需实现具体的认证信息提取逻辑(attemptAuthentication 方法)。
OncePerRequestFilter
单个过滤器的基类(确保一次请求只执行一次),实现具体的过滤逻辑(如认证、日志等)
GenericFilterBean
GenericFilterBean 是一个抽象类,它提供了一个框架来实现自定义的Servlet过滤器。它扩展了Spring的基础功能,允许开发者将Servlet过滤器集成到Spring应用程序上下文中,并利用Spring的依赖注入和属性填充。
移除过滤器(谨慎使用)
@Configuration // 标记为配置类,让 Spring 解析
@EnableWebSecurity // 启用 Spring Security 的 Web 安全支持
public class SecurityConfig {
@Bean
// 配置 SecurityFilterChain,定义安全拦截规则
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception
{
// 1. 构建默认的过滤器链
DefaultSecurityFilterChain defaultChain = http.build();
// 2. 获取默认过滤器列表
List<Filter> filters = defaultChain.getFilters();
// 3. 移除目标过滤器(例如移除UsernamePasswordAuthenticationFilter)
filters.removeIf(filter -> filter.getClass() == UsernamePasswordAuthenticationFilter.class);
// 4. 构建新的过滤器链(替换默认过滤器列表)
return new DefaultSecurityFilterChain(defaultChain.getRequestMatcher(), filters);
}
}
异常处理
Spring Security 的异常处理体系围绕认证(Authentication) 和授权(Authorization) 两大核心流程设计,包含多种内置异常类型及对应的处理机制。以下是主要的异常类型、触发场景及处理方式:
认证相关异常
AuthenticationException 是所有认证相关异常的父类,发生在用户身份验证过程中(如登录失败、令牌无效等)
| 异常类型 | 触发场景 |
|---|---|
| BadCredentialsException | 凭证错误(如密码错误、JWT 令牌无效 / 篡改、验证码错误)。 |
| UsernameNotFoundException | 用户名不存在(如数据库中查询不到该用户)。 |
| AccountExpiredException | 用户账号已过期(需管理员重置)。 |
| LockedException | 用户账号被锁定(如多次登录失败后触发)。 |
| DisabledException | 用户账号被禁用(如管理员手动禁用)。 |
| InsufficientAuthenticationException | 认证信息不足(如匿名用户访问需认证的资源,或令牌缺少必要信息)。 |
| AuthenticationServiceException | 认证过程中发生服务异常(如数据库连接失败、第三方认证服务不可用)。 |
| InvalidJwtException(扩展) | JWT 令牌格式错误、签名无效、过期等(通常由 JWT 工具类抛出)。 |
授权相关异常
AccessDeniedException 是授权阶段的核心异常,发生在用户已认证但权限不足时
| 异常类型 | 触发场景 |
|---|---|
| AccessDeniedException | 已认证用户访问无权限的资源(如普通用户访问管理员接口)。 |
| CsrfException | CSRF 令牌验证失败(如请求中 CSRF 令牌缺失或无效)。 |
异常处理过程
以默认情况下UsernamePasswordAuthenticationFilter过滤器为例子:

可以修改UsernamePasswordAuthenticationFilter的失败处理器(AuthenticationFailureHandler failureHandler),改变异常处理逻辑
http.objectPostProcessor(new ObjectPostProcessor<Object>() {
@Override
public <O extends Object> O postProcess(O object) {
if (object instanceof UsernamePasswordAuthenticationFilter) {
((UsernamePasswordAuthenticationFilter)object).setAuthenticationFailureHandler(new AuthenticationEntryPointFailureHandler(new Http403ForbiddenEntryPoint()));
}
return object;
}
})
修改成了登录失败返回403页面

自定义过滤器异常处理
首先配置HttpSecurity http的异常处理逻辑
http.exceptionHandling(ex -> ex
.authenticationEntryPoint((request, response, exp) -> {
// 处理未认证:返回 401 JSON
response.setContentType("application/json;charset=UTF-8");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("{\"code\":401,\"msg\":\"请先登录\"}");
})
.accessDeniedHandler((request, response, exp) -> {
// 处理权限不足:返回 403 JSON
response.setContentType("application/json;charset=UTF-8");
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.getWriter().write("{\"code\":403,\"msg\":\"权限不足\"}");
})
);
添加自定义过滤器时,必须在ExceptionTranslationFilter过滤器后面,否则自定义过滤器抛出异常,ExceptionTranslationFilter捕获不到异常,例子:
JwtAuthenticationProcessingFilter是我的自定义过滤器
http.addFilterAfter(JwtAuthenticationProcessingFilter.createJwtAuthenticationProcessingFilter(authenticationManager), ExceptionTranslationFilter.class);
2272

被折叠的 条评论
为什么被折叠?



