在OAuth2中 自定义tokenServices来提供个性化服务,每次刷新token并让原token在5分钟内有效
这样写有几个好处:
- 不需要使用拦截器来让设备异地登录失效,大大提升吞吐量
- 每次登录都刷新了access_token,并且加满了过期时间,不会出现过期时间到了要重新登录的问题。
- 可以自定义在获取新token后,让原token5分钟内仍有效
直接复制DefaultTokenServices代码进行修改
所有的代码保留,唯独要修改的是createAccessToken这个方法
@Transactional
public OAuth2AccessToken createAccessToken(OAuth2Authentication authentication) throws AuthenticationException {
OAuth2AccessToken existingAccessToken = tokenStore.getAccessToken(authentication);
OAuth2RefreshToken refreshToken = null;
if (existingAccessToken != null) {
if (existingAccessToken.isExpired()) {
if (existingAccessToken.getRefreshToken() != null) {
refreshToken = existingAccessToken.getRefreshToken();
// The token store could remove the refresh token when the
// access token is removed, but we want to
// be sure...
tokenStore.removeRefreshToken(refreshToken);
}
tokenStore.removeAccessToken(existingAccessToken);
}
else {
// modified by pancg 2020-03-02
// 根据当前开放平台功能设计调整为每次获取新token并让老token在5分钟内有效
// 1.这里是原来的实现
// Re-store the access token in case the authentication has changed
//tokenStore.storeAccessToken(existingAccessToken, authentication);
//return existingAccessToken;
// 2.让原token在token更新后5分钟内仍有效
// Re-store the access token in case the authentication has changed
tokenStore.storeAccessToken(createAccessTokenInNextFiveMinute(existingAccessToken, authentication), authentication);
// 3.下面是创建新token并返回
// Only create a new refresh token if there wasn't an existing one
// associated with an expired access token.
// Clients might be holding existing refresh tokens, so we re-use it in
// the case that the old access token
// expired.
if (refreshToken == null) {
refreshToken = createRefreshToken(authentication);
}
// But the refresh token itself might need to be re-issued if it has
// expired.
else if (refreshToken instanceof ExpiringOAuth2RefreshToken) {
ExpiringOAuth2RefreshToken expiring = (ExpiringOAuth2RefreshToken) refreshToken;
if (System.currentTimeMillis() > expiring.getExpiration().getTime()) {
refreshToken = createRefreshToken(authentication);
}
}
OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken);
tokenStore.storeAccessToken(accessToken, authentication);
// In case it was modified
refreshToken = accessToken.getRefreshToken();
if (refreshToken != null) {
tokenStore.storeRefreshToken(refreshToken, authentication);
}
return accessToken;
}
}
// Only create a new refresh token if there wasn't an existing one
// associated with an expired access token.
// Clients might be holding existing refresh tokens, so we re-use it in
// the case that the old access token
// expired.
if (refreshToken == null) {
refreshToken = createRefreshToken(authentication);
}
// But the refresh token itself might need to be re-issued if it has
// expired.
else if (refreshToken instanceof ExpiringOAuth2RefreshToken) {
ExpiringOAuth2RefreshToken expiring = (ExpiringOAuth2RefreshToken) refreshToken;
if (System.currentTimeMillis() > expiring.getExpiration().getTime()) {
refreshToken = createRefreshToken(authentication);
}
}
OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken);
tokenStore.storeAccessToken(accessToken, authentication);
// In case it was modified
refreshToken = accessToken.getRefreshToken();
if (refreshToken != null) {
tokenStore.storeRefreshToken(refreshToken, authentication);
}
return accessToken;
}
/**
* @description 创建一个使原token在接下来5分钟有效的token
* @added by pancg
* @param
* @return
*/
private OAuth2AccessToken createAccessTokenInNextFiveMinute(OAuth2AccessToken existingAccessToken, OAuth2Authentication authentication) {
final int validitySeconds = 5 * 60;
DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(existingAccessToken.getValue());
//DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(UUID.randomUUID().toString());
//int validitySeconds = getAccessTokenValiditySeconds(authentication.getOAuth2Request());
if (validitySeconds > 0) {
token.setExpiration(new Date(System.currentTimeMillis() + (validitySeconds * 1000L)));
}
token.setRefreshToken(existingAccessToken.getRefreshToken());
token.setScope(authentication.getOAuth2Request().getScope());
//return accessTokenEnhancer != null ? accessTokenEnhancer.enhance(token, authentication) : token;
return token;
}
最后在AuthorizationServerConfig增加如下内容,其中endpoints.tokenServices(tokenServices(endpoints));就是把我们新写的SingleTokenServices给配置进来。
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenServices(tokenServices(endpoints));
endpoints.authenticationManager(this.authenticationManager);
endpoints.tokenStore(tokenStore());
// 授权码模式下,code存储
// endpoints.authorizationCodeServices(new JdbcAuthorizationCodeServices(dataSource));
endpoints.authorizationCodeServices(redisAuthorizationCodeServices);
if (storeWithJwt) {
endpoints.accessTokenConverter(accessTokenConverter());
}
}
private SingleTokenServices tokenServices(AuthorizationServerEndpointsConfigurer endpoints) {
SingleTokenServices tokenServices = new SingleTokenServices();
tokenServices.setTokenStore(tokenStore());
tokenServices.setSupportRefreshToken(true);//支持刷新token
tokenServices.setReuseRefreshToken(true);
tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
addUserDetailsService(tokenServices, this.userDetailsService);
return tokenServices;
}
private void addUserDetailsService(SingleTokenServices tokenServices, UserDetailsService userDetailsService) {
if (userDetailsService != null) {
PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
provider.setPreAuthenticatedUserDetailsService(new UserDetailsByNameServiceWrapper<>(
userDetailsService));
tokenServices.setAuthenticationManager(new ProviderManager(Arrays.asList(provider)));
}
}
参考:https://my.oschina.net/u/3768341/blog/2998273

浙公网安备 33010602011771号