默认情况下刷新token后原token会立马不可用。但是在某些情况下我们需要刷新token后原token在一定时间内继续可用(例如微信的刷新token)。
通过查看DefaultTokenServices中的刷新token方法refreshAccessToken可以看到生成新的token后会调用removeAccessTokenUsingRefreshToken方法,此方法默认会删除存储的相关token信息
private void removeAccessTokenUsingRefreshToken(String refreshToken) {
byte[] key = serializeKey(REFRESH_TO_ACCESS + refreshToken);
List<Object> results = null;
RedisConnection conn = getConnection();
try {
conn.openPipeline();
conn.get(key);
conn.del(key);
results = conn.closePipeline();
} finally {
conn.close();
}
if (results == null) {
return;
}
byte[] bytes = (byte[]) results.get(0);
String accessToken = deserializeString(bytes);
if (accessToken != null) {
removeAccessToken(accessToken);
}
}
所以就需要重写该方法设置不立即删除
首先需要自定义tokenStore
public class OAuth2AuthorizationConfiguration extends AuthorizationServerConfigurerAdapter {
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.accessTokenConverter(new FrameworkAccessTokenConverter());
endpoints.authorizationCodeServices(meiceAuthorizationCodeService)
.tokenEnhancer(jwtAccessTokenConverter())
.reuseRefreshTokens(false)
// 使用自定义tokenStore管理tongken
.tokenStore(meiceTokenStore)
.userDetailsService(meiceUserDetailsService)
.authenticationManager(authenticationManager)
.setClientDetailsService(meiceClientDetailsService);
endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
endpoints.exceptionTranslator(new MeiceWebResponseExceptionTranslator());
//使用自定义granter以返回refresh_token.(默认granter不返回)
endpoints.tokenGranter(new CompositeTokenGranter(getMeiceTokenGranters()));
}
}
//自定义tokenStore(其他代码参考org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore)
public class IRedisTokenStore implements TokenStore {
@Override
public void removeAccessTokenUsingRefreshToken(OAuth2RefreshToken refreshToken) {
removeAccessTokenUsingRefreshToken(refreshToken.getValue());
}
private void removeAccessTokenUsingRefreshToken(String refreshToken) {
String token = (String) this.redisTemplate.opsForValue().get(REFRESH_TO_ACCESS + refreshToken);
if (token != null) {
//设置刷新后5分钟内继续可用
redisTemplate.expire(ACCESS + token, 300, TimeUnit.SECONDS);
}
}
}
至此Token将在刷新后5分钟过期删除.