升级Spring Security后OAuth2Authentication类缺失问题修复咨询
问题描述
将项目从JDK11升级至JDK17,同步把Spring Boot版本从2.1.6.RELEASE更新到2.7.18,导致spring-security-oauth2-client和spring-security-oauth2-resource-server依赖升级到5.7.11。编译时出现OAuth2Authentication、OAuth2AuthenticationDetails类找不到的问题,原获取token的代码逻辑失效。尝试替换为OAuth2AuthenticationToken和JwtAuthenticationToken的逻辑仍报错,求修复方案。
原代码
public static AuthenticatePerson getPerson(){ String token = null; var person = new AuthenticatePerson(); Authentication principal = SecurityContextHolder.getContext() .getAuthentication(); if (principal instanceof OAuth2Authentication){ OAuth2Authentication authentication = (OAuth2Authentication) principal; Object details = authentication.getDetails(); if (details instanceof OAuth2AuthenticationDetails) { OAuth2AuthenticationDetails oauthsDetails = (OAuth2AuthenticationDetails) details; token = oauthsDetails.getTokenValue(); } } try { DecodedJWT jwt = JWT.decode(token); person.setName(jwt.getClaims().get("name").asString()); person.setEmail(jwt.getClaims().get("mail").asString()); person.setGroupe(jwt.getClaims().get("Group").asString()); } catch (JWTDecodeException exception){ //Invalid token } return person; }
尝试的代码
if (principal instanceof OAuth2AuthenticationToken){ OAuth2AuthenticationToken authenticationToken = (OAuth2AuthenticationToken) principal; token = authenticationToken.getAuthorizedClientRegistrationId(); }
if (principal instanceof JwtAuthenticationToken) { JwtAuthenticationToken jwtAuth = (JwtAuthenticationToken) principal; token = jwtAuth.getToken().getTokenValue(); }
修复方案
1. 明确项目的OAuth2角色
Spring Security 5.x彻底重构了OAuth2的API,旧的OAuth2Authentication、OAuth2AuthenticationDetails已被移除,替代方案分两种核心场景:OAuth2资源服务器(接收并验证JWT令牌)和OAuth2客户端(持有令牌调用第三方服务),需根据项目实际角色选择对应逻辑。
2. 资源服务器场景(接收JWT令牌)
如果你的项目是资源服务器,SecurityContext中的Authentication是JwtAuthenticationToken,Spring Security已经完成了JWT的解析,直接使用已解析的数据即可,无需手动解码:
public static AuthenticatePerson getPerson(){ AuthenticatePerson person = new AuthenticatePerson(); Authentication principal = SecurityContextHolder.getContext().getAuthentication(); if (principal instanceof JwtAuthenticationToken jwtAuth) { // 获取token字符串 String token = jwtAuth.getToken().getTokenValue(); // 直接从已解析的Jwt对象提取Claims,避免手动解码的异常 Jwt jwt = jwtAuth.getToken(); person.setName(jwt.getClaimAsString("name")); person.setEmail(jwt.getClaimAsString("mail")); person.setGroupe(jwt.getClaimAsString("Group")); } return person; }
3. OAuth2客户端场景(持有令牌调用第三方服务)
如果你的项目是OAuth2客户端,SecurityContext中的Authentication是OAuth2AuthenticationToken,但该对象本身不存储token,需要通过OAuth2AuthorizedClientService获取授权客户端来拿到token:
首先注入授权客户端服务:
@Autowired private OAuth2AuthorizedClientService authorizedClientService;
然后修改获取逻辑:
public AuthenticatePerson getPerson(){ AuthenticatePerson person = new AuthenticatePerson(); Authentication principal = SecurityContextHolder.getContext().getAuthentication(); if (principal instanceof OAuth2AuthenticationToken authToken) { // 根据客户端ID和用户名加载已授权的客户端 OAuth2AuthorizedClient authorizedClient = authorizedClientService.loadAuthorizedClient( authToken.getAuthorizedClientRegistrationId(), authToken.getName() ); if (authorizedClient != null) { // 获取token字符串 String token = authorizedClient.getAccessToken().getTokenValue(); // 解码JWT获取Claims(如果业务需要) try { DecodedJWT jwt = JWT.decode(token); person.setName(jwt.getClaims().get("name").asString()); person.setEmail(jwt.getClaims().get("mail").asString()); person.setGroupe(jwt.getClaims().get("Group").asString()); } catch (JWTDecodeException exception){ // 处理无效token的业务逻辑 } } } return person; }
4. 依赖检查
确保项目引入了正确的Spring Security OAuth2依赖:
- 资源服务器依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-resource-server</artifactId> </dependency>
- OAuth2客户端依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-client</artifactId> </dependency>
内容的提问来源于stack exchange,提问作者paymer

