前言
在之前的案例中,认证获取到了访问令牌信息,但是这些信息完全不够,比如没有登录用户名,如果还需要添加其他额外信息应该怎么做呢?
源码分析
创建令牌
之前我们分析过,DefaultTokenServices在其createAccessToken方法中会进行令牌的创建和存储。
private OAuth2AccessToken createAccessToken(OAuth2Authentication authentication, OAuth2RefreshToken refreshToken) {
// 1. 使用UUID创建一个默认的令牌
DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(UUID.randomUUID().toString());
// 2. 调用ClientDetailsService 查询令牌的过期时间
int validitySeconds = getAccessTokenValiditySeconds(authentication.getOAuth2Request());
// 3. 设置令牌的过期时间 Mon Nov 15 10:11:16 CST 2021
if (validitySeconds > 0) {
token.setExpiration(new Date(System.currentTimeMillis() + (validitySeconds * 1000L)));
}
// 4. 设置刷新令牌 授权范围
token.setRefreshToken(refreshToken);
token.setScope(authentication.getOAuth2Request().getScope());
// 5. 是否设置了令牌增强,如有则增强后再返回
return accessTokenEnhancer != null ? accessTokenEnhancer.enhance(token, authentication) : token;
}
可以看到在第5 步骤中,会调用TokenEnhancer接口的enhance方法对令牌进行增强处理。
TokenEnhancer
TokenEnhancer接口位于org.springframework.security.oauth2.provider.token
包下,它的主要作用是在令牌存储之前,对令牌进行增强处理,只声明了一个enhance方法。
public interface TokenEnhancer {
/**
* 增强令牌
*
* @param accessToken 当前具有scope及过期时间的访问令牌
* @param authentication 当前认证用户信息
* @return 添加了额外信息的新令牌
*/
OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication);
}
使用案例
1. 实现TokenEnhancer 接口
实现TokenEnhancer 接口,重写enhance方法,该方法传入了OAuth2AccessToken 及OAuth2Authentication 对象,所以可以获取到认证信息,添加到令牌对象中,也可以添加其他额外信息。
public class MyTokenEnhancer implements TokenEnhancer {
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
Map<String, Object> additionalInformation = new HashMap<>();
// 1. 获取认证信息
// 客户端
String clientId = authentication.getOAuth2Request().getClientId();// 客户端ID
Set<String> resourceIds = authentication.getOAuth2Request().getResourceIds(); // 资源集合
// 用户
Authentication userAuthentication = authentication.getUserAuthentication();
Object principal = userAuthentication.getPrincipal();
if (principal instanceof User){
User user= (User) principal;
additionalInformation.put("userName", user.getUsername());
}
// 2.设置到accessToken中
additionalInformation.put("resourceIds", resourceIds);
additionalInformation.put("clientId", clientId);
additionalInformation.put("deptId", "0001");
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInformation);
return accessToken;
}
}
2. 添加配置
在AuthorizationServer配置类中声明TokenEnhancer Bean对象,然后在端点配置类中添加令牌增强器。
// 端点配置
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
// 配置端点允许的请求方式
endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
// 配置认证管理器
endpoints.authenticationManager(authenticationManager);
// 自定义异常翻译器,用于处理OAuth2Exception
endpoints.exceptionTranslator(myWebResponseExceptionTranslator);
// 重新组装令牌颁发者,加入自定义授权模式
endpoints.tokenGranter(getTokenGranter(endpoints));
/* // 添加JWT令牌
// JWT令牌转换器
endpoints.accessTokenConverter(jwtAccessTokenConverter);
// JWT 存储令牌*/
endpoints.tokenStore(redisTokenStore);
// 刷新令牌模式添加 userDetailsService
endpoints.userDetailsService(userDetailsService);
// 添加令牌增强器
endpoints.tokenEnhancer(tokenEnhancer());
}
@Bean
public TokenEnhancer tokenEnhancer() {
return new MyTokenEnhancer();
}
3. 测试
访问令牌端点,发现返回了自定义的额外信息。