1. 概述
Spring Security 帮我们处理了认证信息的接收与解析,开发者无需从头实现。
本文将聚焦一个实用功能:如何在处理请求的代码中,便捷地获取当前的 SecurityContext 信息。你会看到,相比传统方式,新注解能让代码更简洁、更清晰。
2. @CurrentSecurityContext 注解简介
过去,获取认证信息通常需要写这样的样板代码:
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
虽然可行,但侵入性强,且每次都要重复。✅ 现在有了更优雅的方案:@CurrentSecurityContext
注解。
这个注解的核心价值在于:
- ✅ 声明式编程:直接在方法参数上声明依赖,无需手动调用静态工具类
- ✅ 依赖注入:
Authentication
或Principal
对象可被自动注入 - ✅ 灵活取值:结合 SpEL(Spring 表达式语言),可精确提取上下文中的任意属性
接下来,我们将通过实际例子展示如何用它获取 Authentication
和 Principal
,并附上测试验证。
3. Maven 依赖配置
如果你使用的是较新版本的 Spring Boot,只需引入标准安全模块:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
若非 Spring Boot 项目,则直接引入 spring-security-core
:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>6.1.5</version>
</dependency>
⚠️ 注意:@CurrentSecurityContext
在 Spring Security 5.2+ 版本中可用,建议保持版本一致性。
4. 使用 @CurrentSecurityContext 实现上下文注入
@CurrentSecurityContext
支持通过 SpEL 表达式指定要注入的对象类型。SpEL 会结合参数类型进行解析,类型安全可通过 errorOnInvalidType
参数开启校验。
4.1 获取 Authentication 对象
最常见需求之一是获取完整的 Authentication
对象,比如查看认证详情(details):
@GetMapping("/authentication")
public Object getAuthentication(@CurrentSecurityContext(expression = "authentication")
Authentication authentication) {
return authentication.getDetails();
}
📌 关键点:
expression = "authentication"
表示注入SecurityContext.authentication
本身- 参数类型为
Authentication
,Spring 会自动完成类型匹配
测试示例
@Test
public void givenOAuth2Context_whenAccessingAuthentication_ThenRespondTokenDetails() {
ClientCredentialsResourceDetails resourceDetails =
getClientCredentialsResourceDetails("user123", java.util.Collections.singletonList("read"));
OAuth2RestTemplate restTemplate = getOAuth2RestTemplate(resourceDetails);
String authentication = executeGetRequest(restTemplate, "/authentication");
// 因 remoteAddress 和 tokenValue 动态生成,使用正则匹配结构
Pattern pattern = Pattern.compile("\\{\"remoteAddress\":\".*"
+ "\",\"sessionId\":null,\"tokenValue\":\".*"
+ "\",\"tokenType\":\"Bearer\",\"decodedDetails\":null}");
assertTrue("authentication 结构应匹配", pattern.matcher(authentication).matches());
}
✅ 踩坑提示:测试中不要断言具体 token 值,因其每次请求都不同。建议用正则校验 JSON 结构即可。
4.2 获取 Principal 对象
如果只需要用户身份标识(如用户名),可以直接注入 Principal
:
@GetMapping("/principal")
public String getPrincipal(@CurrentSecurityContext(expression = "authentication.principal")
Principal principal) {
return principal.getName();
}
📌 关键点:
- SpEL 表达式为
authentication.principal
,指向认证主体 - 参数类型为
Principal
,框架自动完成转换
测试示例
@Test
public void givenOAuth2Context_whenAccessingPrincipal_ThenRespondUser123() {
ClientCredentialsResourceDetails resourceDetails =
getClientCredentialsResourceDetails("user123", java.util.Collections.singletonList("read"));
OAuth2RestTemplate restTemplate = getOAuth2RestTemplate(resourceDetails);
String principal = executeGetRequest(restTemplate, "/principal");
assertEquals("user123", principal);
}
✅ 简单粗暴:测试中我们明确知道 client credentials 中设置的用户名是 user123
,因此可以直接断言返回值。
5. 总结
@CurrentSecurityContext
是一个被低估但极其实用的注解,它让安全上下文的访问变得:
- ✅ 更简洁:告别
SecurityContextHolder.getContext()
的冗长调用 - ✅ 更安全:支持类型检查,减少运行时错误
- ✅ 更灵活:通过 SpEL 可定制任意属性提取逻辑
在实际项目中,尤其在 REST 接口或自定义鉴权逻辑中,推荐优先使用此注解替代手动获取上下文的方式。
源码示例已托管至 GitHub:https://github.com/example/spring-security-current-context-demo