Spring security 如何在spring security中更新刷新令牌的到期时间而不生成新的刷新令牌?

Spring security 如何在spring security中更新刷新令牌的到期时间而不生成新的刷新令牌?,spring-security,spring-security-oauth2,spring-oauth2,Spring Security,Spring Security Oauth2,Spring Oauth2,到目前为止,我已经在我的应用程序中配置了密码授予类型,并且工作正常。当我点击/oauth/token并传递CI&CS&username&password以及密码授予类型时,我会获得访问令牌、刷新令牌、到期时间和一些其他信息 当访问令牌过期时,应用程序使用刷新令牌获取新的访问令牌 但我的问题是,当应用程序使用刷新令牌获取新的访问令牌时,如何延长刷新令牌的到期时间。例如,如果用户在过去30天内没有使用该应用程序,则只有refresh_令牌应该过期 通过谷歌搜索,我找到了一条出路 @Override

到目前为止,我已经在我的应用程序中配置了密码授予类型,并且工作正常。当我点击
/oauth/token
并传递CI&CS&username&password以及密码授予类型时,我会获得
访问令牌、刷新令牌、到期时间和一些其他信息

访问令牌
过期时,应用程序使用
刷新令牌
获取新的
访问令牌

但我的问题是,当应用程序使用刷新令牌获取新的访问令牌时,如何延长刷新令牌的到期时间。例如,如果用户在过去30天内没有使用该应用程序,则只有refresh_令牌应该过期

通过谷歌搜索,我找到了一条出路

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    endpoints.tokenStore(redisTokenStore).userApprovalHandler(userApprovalHandler)
            .authenticationManager(authenticationManager)
            .tokenEnhancer(tokenEnhancer)

            .reuseRefreshTokens(false);
}
当我们尝试使用刷新令牌获取访问令牌时,reuseRefreshTokens(false)将生成新的
刷新令牌
访问令牌
。当生成新的刷新令牌时,它会设置一个新的到期时间(比如说,从生成新的刷新令牌起30天)。但我不想更改刷新令牌


我怎样才能做到这一点呢?

我找到了解决这个问题的办法。我实现了一个
CustomTokenService
,而不是DefaultTokenService。RefreshTokenGranter将调用
getTokenServices().refreshAccessToken(refreshToken,tokenRequest)

这将调用我的
CustomTokenService

@Component
public class CustomTokenServices implements AuthorizationServerTokenServices, ResourceServerTokenServices,
ConsumerTokenServices, InitializingBean{

private int refreshTokenValiditySeconds = 60 * 60 * 24 * 30; // default 30 days.

private int accessTokenValiditySeconds = 60 * 60 * 24; // default 24 hours.

private boolean supportRefreshToken = true;

private boolean reuseRefreshToken = true;

private boolean updateRefreshTokenLastLoginTime = true;

@Autowired
private TokenStore tokenStore;

@Autowired
private ClientDetailsService clientDetailsService;

@Autowired
private TokenEnhancer accessTokenEnhancer;

@Autowired
private AuthenticationManager authenticationManager;

/**
 * Initialize these token services. If no random generator is set, one will be created.
 */
public void afterPropertiesSet() throws Exception {
    Assert.notNull(tokenStore, "tokenStore must be set");
}

@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 {
            // Re-store the access token in case the authentication has changed
            tokenStore.storeAccessToken(existingAccessToken, authentication);
            return existingAccessToken;
        }
    }

    // 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;

}

@Transactional(noRollbackFor={InvalidTokenException.class, InvalidGrantException.class})
public OAuth2AccessToken refreshAccessToken(String refreshTokenValue, TokenRequest tokenRequest)
        throws AuthenticationException {

    if (!supportRefreshToken) {
        throw new InvalidGrantException("Invalid refresh token: " + refreshTokenValue);
    }

    OAuth2RefreshToken refreshToken = tokenStore.readRefreshToken(refreshTokenValue);
    if (refreshToken == null) {
        throw new InvalidGrantException("Invalid refresh token: " + refreshTokenValue);
    }

    OAuth2Authentication authentication = tokenStore.readAuthenticationForRefreshToken(refreshToken);
    if (this.authenticationManager != null && !authentication.isClientOnly()) {
        // The client has already been authenticated, but the user authentication might be old now, so give it a
        // chance to re-authenticate.
        Authentication user = new PreAuthenticatedAuthenticationToken(authentication.getUserAuthentication(), "", authentication.getAuthorities());
        user = authenticationManager.authenticate(user);
        Object details = authentication.getDetails();
        authentication = new OAuth2Authentication(authentication.getOAuth2Request(), user);
        authentication.setDetails(details);
    }
    String clientId = authentication.getOAuth2Request().getClientId();
    if (clientId == null || !clientId.equals(tokenRequest.getClientId())) {
        throw new InvalidGrantException("Wrong client for this refresh token: " + refreshTokenValue);
    }

    // clear out any access tokens already associated with the refresh
    // token.
    tokenStore.removeAccessTokenUsingRefreshToken(refreshToken);

    if (isExpired(refreshToken)) {
        tokenStore.removeRefreshToken(refreshToken);
        throw new InvalidTokenException("Invalid refresh token (expired): " + refreshToken);
    }

    authentication = createRefreshedAuthentication(authentication, tokenRequest);

    if (!reuseRefreshToken) {
        tokenStore.removeRefreshToken(refreshToken);
        refreshToken = createRefreshToken(authentication);
    }else if(updateRefreshTokenLastLoginTime) {
        String refreshTokn = refreshToken.getValue();
        tokenStore.removeRefreshToken(refreshToken);
        refreshToken = updateRefreshToken(authentication,refreshTokn);
    }

    OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken);
    tokenStore.storeAccessToken(accessToken, authentication);
    if (!reuseRefreshToken) {
        tokenStore.storeRefreshToken(accessToken.getRefreshToken(), authentication);
    }else if(updateRefreshTokenLastLoginTime) {
        tokenStore.storeRefreshToken(accessToken.getRefreshToken(), authentication);
    }
    return accessToken;
}

public OAuth2AccessToken getAccessToken(OAuth2Authentication authentication) {
    return tokenStore.getAccessToken(authentication);
}

/**
 * Create a refreshed authentication.
 * 
 * @param authentication The authentication.
 * @param request The scope for the refreshed token.
 * @return The refreshed authentication.
 * @throws InvalidScopeException If the scope requested is invalid or wider than the original scope.
 */
private OAuth2Authentication createRefreshedAuthentication(OAuth2Authentication authentication, TokenRequest request) {
    OAuth2Authentication narrowed = authentication;
    Set<String> scope = request.getScope();
    OAuth2Request clientAuth = authentication.getOAuth2Request().refresh(request);
    if (scope != null && !scope.isEmpty()) {
        Set<String> originalScope = clientAuth.getScope();
        if (originalScope == null || !originalScope.containsAll(scope)) {
            throw new InvalidScopeException("Unable to narrow the scope of the client authentication to " + scope
                    + ".", originalScope);
        }
        else {
            clientAuth = clientAuth.narrowScope(scope);
        }
    }
    narrowed = new OAuth2Authentication(clientAuth, authentication.getUserAuthentication());
    return narrowed;
}

protected boolean isExpired(OAuth2RefreshToken refreshToken) {
    if (refreshToken instanceof ExpiringOAuth2RefreshToken) {
        ExpiringOAuth2RefreshToken expiringToken = (ExpiringOAuth2RefreshToken) refreshToken;
        return expiringToken.getExpiration() == null
                || System.currentTimeMillis() > expiringToken.getExpiration().getTime();
    }
    return false;
}

public OAuth2AccessToken readAccessToken(String accessToken) {
    return tokenStore.readAccessToken(accessToken);
}

public OAuth2Authentication loadAuthentication(String accessTokenValue) throws AuthenticationException,
        InvalidTokenException {
    OAuth2AccessToken accessToken = tokenStore.readAccessToken(accessTokenValue);
    if (accessToken == null) {
        throw new InvalidTokenException("Invalid access token: " + accessTokenValue);
    }
    else if (accessToken.isExpired()) {
        tokenStore.removeAccessToken(accessToken);
        throw new InvalidTokenException("Access token expired: " + accessTokenValue);
    }

    OAuth2Authentication result = tokenStore.readAuthentication(accessToken);
    if (result == null) {
        // in case of race condition
        throw new InvalidTokenException("Invalid access token: " + accessTokenValue);
    }
    if (clientDetailsService != null) {
        String clientId = result.getOAuth2Request().getClientId();
        try {
            clientDetailsService.loadClientByClientId(clientId);
        }
        catch (ClientRegistrationException e) {
            throw new InvalidTokenException("Client not valid: " + clientId, e);
        }
    }
    return result;
}

public String getClientId(String tokenValue) {
    OAuth2Authentication authentication = tokenStore.readAuthentication(tokenValue);
    if (authentication == null) {
        throw new InvalidTokenException("Invalid access token: " + tokenValue);
    }
    OAuth2Request clientAuth = authentication.getOAuth2Request();
    if (clientAuth == null) {
        throw new InvalidTokenException("Invalid access token (no client id): " + tokenValue);
    }
    return clientAuth.getClientId();
}

public boolean revokeToken(String tokenValue) {
    OAuth2AccessToken accessToken = tokenStore.readAccessToken(tokenValue);
    if (accessToken == null) {
        return false;
    }
    if (accessToken.getRefreshToken() != null) {
        tokenStore.removeRefreshToken(accessToken.getRefreshToken());
    }
    tokenStore.removeAccessToken(accessToken);
    return true;
}

private OAuth2RefreshToken createRefreshToken(OAuth2Authentication authentication) {
    if (!isSupportRefreshToken(authentication.getOAuth2Request())) {
        return null;
    }
    int validitySeconds = getRefreshTokenValiditySeconds(authentication.getOAuth2Request());
    String value = UUID.randomUUID().toString();
    if (validitySeconds > 0) {
        return new DefaultExpiringOAuth2RefreshToken(value, new Date(System.currentTimeMillis()
                + (validitySeconds * 1000L)));
    }
    return new DefaultOAuth2RefreshToken(value);
}

private OAuth2RefreshToken updateRefreshToken(OAuth2Authentication authentication,String ref_tokn) {
    if (!isSupportRefreshToken(authentication.getOAuth2Request())) {
        return null;
    }
    int validitySeconds = getRefreshTokenValiditySeconds(authentication.getOAuth2Request());
    String value = ref_tokn;
    if (validitySeconds > 0) {
        return new DefaultExpiringOAuth2RefreshToken(value, new Date(System.currentTimeMillis()
                + (validitySeconds * 1000L)));
    }
    return new DefaultOAuth2RefreshToken(value);
}

private OAuth2AccessToken createAccessToken(OAuth2Authentication authentication, OAuth2RefreshToken refreshToken) {
    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(refreshToken);
    token.setScope(authentication.getOAuth2Request().getScope());

    return accessTokenEnhancer != null ? accessTokenEnhancer.enhance(token, authentication) : token;
}

/**
 * The access token validity period in seconds
 * 
 * @param clientAuth the current authorization request
 * @return the access token validity period in seconds
 */
protected int getAccessTokenValiditySeconds(OAuth2Request clientAuth) {
    if (clientDetailsService != null) {
        ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
        Integer validity = client.getAccessTokenValiditySeconds();
        if (validity != null) {
            return validity;
        }
    }
    return accessTokenValiditySeconds;
}

/**
 * The refresh token validity period in seconds
 * 
 * @param clientAuth the current authorization request
 * @return the refresh token validity period in seconds
 */
protected int getRefreshTokenValiditySeconds(OAuth2Request clientAuth) {
    if (clientDetailsService != null) {
        ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
        Integer validity = client.getRefreshTokenValiditySeconds();
        if (validity != null) {
            return validity;
        }
    }
    return refreshTokenValiditySeconds;
}

/**
 * Is a refresh token supported for this client (or the global setting if
 * {@link #setClientDetailsService(ClientDetailsService) clientDetailsService} is not set.
 * 
 * @param clientAuth the current authorization request
 * @return boolean to indicate if refresh token is supported
 */
protected boolean isSupportRefreshToken(OAuth2Request clientAuth) {
    if (clientDetailsService != null) {
        ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
        return client.getAuthorizedGrantTypes().contains("refresh_token");
    }
    return this.supportRefreshToken;
}

/**
 * An access token enhancer that will be applied to a new token before it is saved in the token store.
 * 
 * @param accessTokenEnhancer the access token enhancer to set
 */
public void setTokenEnhancer(TokenEnhancer accessTokenEnhancer) {
    this.accessTokenEnhancer = accessTokenEnhancer;
}

/**
 * The validity (in seconds) of the refresh token. If less than or equal to zero then the tokens will be
 * non-expiring.
 * 
 * @param refreshTokenValiditySeconds The validity (in seconds) of the refresh token.
 */
public void setRefreshTokenValiditySeconds(int refreshTokenValiditySeconds) {
    this.refreshTokenValiditySeconds = refreshTokenValiditySeconds;
}

/**
 * The default validity (in seconds) of the access token. Zero or negative for non-expiring tokens. If a client
 * details service is set the validity period will be read from he client, defaulting to this value if not defined
 * by the client.
 * 
 * @param accessTokenValiditySeconds The validity (in seconds) of the access token.
 */
public void setAccessTokenValiditySeconds(int accessTokenValiditySeconds) {
    this.accessTokenValiditySeconds = accessTokenValiditySeconds;
}

/**
 * Whether to support the refresh token.
 * 
 * @param supportRefreshToken Whether to support the refresh token.
 */
public void setSupportRefreshToken(boolean supportRefreshToken) {
    this.supportRefreshToken = supportRefreshToken;
}

/**
 * Whether to reuse refresh tokens (until expired).
 * 
 * @param reuseRefreshToken Whether to reuse refresh tokens (until expired).
 */
public void setReuseRefreshToken(boolean reuseRefreshToken) {
    this.reuseRefreshToken = reuseRefreshToken;
}

/**
 * The persistence strategy for token storage.
 * 
 * @param tokenStore the store for access and refresh tokens.
 */
public void setTokenStore(TokenStore tokenStore) {
    this.tokenStore = tokenStore;
}

/**
 * An authentication manager that will be used (if provided) to check the user authentication when a token is
 * refreshed.
 * 
 * @param authenticationManager the authenticationManager to set
 */
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
    this.authenticationManager = authenticationManager;
}

/**
 * The client details service to use for looking up clients (if necessary). Optional if the access token expiry is
 * set globally via {@link #setAccessTokenValiditySeconds(int)}.
 * 
 * @param clientDetailsService the client details service
 */
public void setClientDetailsService(ClientDetailsService clientDetailsService) {
    this.clientDetailsService = clientDetailsService;
}

}
@组件
公共类CustomTokenServices实现AuthorizationServerTokenServices、ResourceServerTokenServices、,
ConsumerTokenServices,初始化bean{
private int-refreshTokenValiditySeconds=60*60*24*30;//默认为30天。
private int-accessTokenValiditySeconds=60*60*24;//默认24小时。
私有布尔supportRefreshToken=true;
私有布尔reuseRefreshToken=true;
私有布尔值updateRefreshTokenLastLoginTime=true;
@自动连线
私人代币店;
@自动连线
私有客户端详细信息服务客户端详细信息服务;
@自动连线
专用令牌增强器访问令牌增强器;
@自动连线
私人AuthenticationManager AuthenticationManager;
/**
*初始化这些令牌服务。如果未设置随机生成器,将创建一个。
*/
public void afterPropertieSet()引发异常{
notNull(令牌存储,“必须设置令牌存储”);
}
@交易的
公共OAuth2AccessToken createAccessToken(OAuth2Authentication身份验证)引发AuthenticationException{
OAuth2AccessToken existingAccessToken=tokenStore.getAccessToken(身份验证);
OAuth2RefreshToken refreshToken=null;
if(existingAccessToken!=null){
if(existingAccessToken.isExpired()){
如果(existingAccessToken.getRefreshToken()!=null){
refreshToken=existingAccessToken.getRefreshToken();
//令牌存储区可以在以下情况下删除刷新令牌:
//访问令牌已删除,但我们希望
//一定要。。。
tokenStore.removeRefreshToken(刷新令牌);
}
removeAccessToken(existingAccessToken);
}
否则{
//如果身份验证已更改,请重新存储访问令牌
storeAccessToken(existingAccessToken,身份验证);
返回现有AccessToken;
}
}
//仅在没有现有刷新令牌的情况下创建新的刷新令牌
//与过期的访问令牌关联。
//客户端可能持有现有的刷新令牌,因此我们在
//旧的访问令牌
//过期了。
if(refreshttoken==null){
refreshToken=createRefreshToken(身份验证);
}
//但是刷新令牌本身可能需要重新发布,如果它已经
//过期了。
else if(refreshToken instanceof ExpiringAuth2RefreshToken){
ExpiringAuth2RefreshToken expiring=(ExpiringAuth2RefreshToken)refreshToken;
if(System.currentTimeMillis()>expiring.getExpiration().getTime()){
refreshToken=createRefreshToken(身份验证);
}
}
OAuth2AccessToken accessToken=createAccessToken(身份验证,刷新令牌);
storeAccessToken(accessToken,身份验证);
//以防它被修改
refreshToken=accessToken.getRefreshToken();
if(刷新令牌!=null){
storeRefreshToken(refreshToken,身份验证);
}
返回accessToken;
}
@事务性(noRollbackFor={InvalidTokenException.class,InvalidGrantException.class})
公共OAuth2AccessToken refreshAccessToken(字符串refreshTokenValue,TokenRequest TokenRequest)
抛出AuthenticationException{
如果(!supportRefreshToken){
抛出新的InvalidGrantException(“无效刷新令牌:+refreshTokenValue”);
}
OAuth2RefreshToken refreshToken=tokenStore.readRefreshToken(refreshTokenValue);
if(refreshttoken==null){
抛出新的InvalidGrantException(“无效刷新令牌:+refreshTokenValue”);
}
OAuth2Authentication authentication=tokenStore.readAuthenticationForRefreshToken(refreshToken);
if(this.authenticationManager!=null&&!authentication.iscliently()){
//客户机已经过身份验证,但是用户身份验证现在可能已经过时了,所以请对其进行验证
//重新验证的机会。
Authentication user=new PreAuthenticationDauthenticationToken(Authentication.getUserAuthentication(),“”,Authentication.getAuthories());
user=authenticationManager.authenticate(用户);
对象详细信息=authentication.getDetails();
身份验证=新的OAuth2Authentication(authentication.getOAuth2Request(),user);
验证。设置详细信息(详细信息);
}
字符串clientId=authentication.getOAuth2Request().getClientId();
if(clientId==null | |!clientId.equals(tokenRequest.g
@Component
public class CustomTokenServices implements AuthorizationServerTokenServices, ResourceServerTokenServices,
ConsumerTokenServices, InitializingBean{

private int refreshTokenValiditySeconds = 60 * 60 * 24 * 30; // default 30 days.

private int accessTokenValiditySeconds = 60 * 60 * 24; // default 24 hours.

private boolean supportRefreshToken = true;

private boolean reuseRefreshToken = true;

private boolean updateRefreshTokenLastLoginTime = true;

@Autowired
private TokenStore tokenStore;

@Autowired
private ClientDetailsService clientDetailsService;

@Autowired
private TokenEnhancer accessTokenEnhancer;

@Autowired
private AuthenticationManager authenticationManager;

/**
 * Initialize these token services. If no random generator is set, one will be created.
 */
public void afterPropertiesSet() throws Exception {
    Assert.notNull(tokenStore, "tokenStore must be set");
}

@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 {
            // Re-store the access token in case the authentication has changed
            tokenStore.storeAccessToken(existingAccessToken, authentication);
            return existingAccessToken;
        }
    }

    // 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;

}

@Transactional(noRollbackFor={InvalidTokenException.class, InvalidGrantException.class})
public OAuth2AccessToken refreshAccessToken(String refreshTokenValue, TokenRequest tokenRequest)
        throws AuthenticationException {

    if (!supportRefreshToken) {
        throw new InvalidGrantException("Invalid refresh token: " + refreshTokenValue);
    }

    OAuth2RefreshToken refreshToken = tokenStore.readRefreshToken(refreshTokenValue);
    if (refreshToken == null) {
        throw new InvalidGrantException("Invalid refresh token: " + refreshTokenValue);
    }

    OAuth2Authentication authentication = tokenStore.readAuthenticationForRefreshToken(refreshToken);
    if (this.authenticationManager != null && !authentication.isClientOnly()) {
        // The client has already been authenticated, but the user authentication might be old now, so give it a
        // chance to re-authenticate.
        Authentication user = new PreAuthenticatedAuthenticationToken(authentication.getUserAuthentication(), "", authentication.getAuthorities());
        user = authenticationManager.authenticate(user);
        Object details = authentication.getDetails();
        authentication = new OAuth2Authentication(authentication.getOAuth2Request(), user);
        authentication.setDetails(details);
    }
    String clientId = authentication.getOAuth2Request().getClientId();
    if (clientId == null || !clientId.equals(tokenRequest.getClientId())) {
        throw new InvalidGrantException("Wrong client for this refresh token: " + refreshTokenValue);
    }

    // clear out any access tokens already associated with the refresh
    // token.
    tokenStore.removeAccessTokenUsingRefreshToken(refreshToken);

    if (isExpired(refreshToken)) {
        tokenStore.removeRefreshToken(refreshToken);
        throw new InvalidTokenException("Invalid refresh token (expired): " + refreshToken);
    }

    authentication = createRefreshedAuthentication(authentication, tokenRequest);

    if (!reuseRefreshToken) {
        tokenStore.removeRefreshToken(refreshToken);
        refreshToken = createRefreshToken(authentication);
    }else if(updateRefreshTokenLastLoginTime) {
        String refreshTokn = refreshToken.getValue();
        tokenStore.removeRefreshToken(refreshToken);
        refreshToken = updateRefreshToken(authentication,refreshTokn);
    }

    OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken);
    tokenStore.storeAccessToken(accessToken, authentication);
    if (!reuseRefreshToken) {
        tokenStore.storeRefreshToken(accessToken.getRefreshToken(), authentication);
    }else if(updateRefreshTokenLastLoginTime) {
        tokenStore.storeRefreshToken(accessToken.getRefreshToken(), authentication);
    }
    return accessToken;
}

public OAuth2AccessToken getAccessToken(OAuth2Authentication authentication) {
    return tokenStore.getAccessToken(authentication);
}

/**
 * Create a refreshed authentication.
 * 
 * @param authentication The authentication.
 * @param request The scope for the refreshed token.
 * @return The refreshed authentication.
 * @throws InvalidScopeException If the scope requested is invalid or wider than the original scope.
 */
private OAuth2Authentication createRefreshedAuthentication(OAuth2Authentication authentication, TokenRequest request) {
    OAuth2Authentication narrowed = authentication;
    Set<String> scope = request.getScope();
    OAuth2Request clientAuth = authentication.getOAuth2Request().refresh(request);
    if (scope != null && !scope.isEmpty()) {
        Set<String> originalScope = clientAuth.getScope();
        if (originalScope == null || !originalScope.containsAll(scope)) {
            throw new InvalidScopeException("Unable to narrow the scope of the client authentication to " + scope
                    + ".", originalScope);
        }
        else {
            clientAuth = clientAuth.narrowScope(scope);
        }
    }
    narrowed = new OAuth2Authentication(clientAuth, authentication.getUserAuthentication());
    return narrowed;
}

protected boolean isExpired(OAuth2RefreshToken refreshToken) {
    if (refreshToken instanceof ExpiringOAuth2RefreshToken) {
        ExpiringOAuth2RefreshToken expiringToken = (ExpiringOAuth2RefreshToken) refreshToken;
        return expiringToken.getExpiration() == null
                || System.currentTimeMillis() > expiringToken.getExpiration().getTime();
    }
    return false;
}

public OAuth2AccessToken readAccessToken(String accessToken) {
    return tokenStore.readAccessToken(accessToken);
}

public OAuth2Authentication loadAuthentication(String accessTokenValue) throws AuthenticationException,
        InvalidTokenException {
    OAuth2AccessToken accessToken = tokenStore.readAccessToken(accessTokenValue);
    if (accessToken == null) {
        throw new InvalidTokenException("Invalid access token: " + accessTokenValue);
    }
    else if (accessToken.isExpired()) {
        tokenStore.removeAccessToken(accessToken);
        throw new InvalidTokenException("Access token expired: " + accessTokenValue);
    }

    OAuth2Authentication result = tokenStore.readAuthentication(accessToken);
    if (result == null) {
        // in case of race condition
        throw new InvalidTokenException("Invalid access token: " + accessTokenValue);
    }
    if (clientDetailsService != null) {
        String clientId = result.getOAuth2Request().getClientId();
        try {
            clientDetailsService.loadClientByClientId(clientId);
        }
        catch (ClientRegistrationException e) {
            throw new InvalidTokenException("Client not valid: " + clientId, e);
        }
    }
    return result;
}

public String getClientId(String tokenValue) {
    OAuth2Authentication authentication = tokenStore.readAuthentication(tokenValue);
    if (authentication == null) {
        throw new InvalidTokenException("Invalid access token: " + tokenValue);
    }
    OAuth2Request clientAuth = authentication.getOAuth2Request();
    if (clientAuth == null) {
        throw new InvalidTokenException("Invalid access token (no client id): " + tokenValue);
    }
    return clientAuth.getClientId();
}

public boolean revokeToken(String tokenValue) {
    OAuth2AccessToken accessToken = tokenStore.readAccessToken(tokenValue);
    if (accessToken == null) {
        return false;
    }
    if (accessToken.getRefreshToken() != null) {
        tokenStore.removeRefreshToken(accessToken.getRefreshToken());
    }
    tokenStore.removeAccessToken(accessToken);
    return true;
}

private OAuth2RefreshToken createRefreshToken(OAuth2Authentication authentication) {
    if (!isSupportRefreshToken(authentication.getOAuth2Request())) {
        return null;
    }
    int validitySeconds = getRefreshTokenValiditySeconds(authentication.getOAuth2Request());
    String value = UUID.randomUUID().toString();
    if (validitySeconds > 0) {
        return new DefaultExpiringOAuth2RefreshToken(value, new Date(System.currentTimeMillis()
                + (validitySeconds * 1000L)));
    }
    return new DefaultOAuth2RefreshToken(value);
}

private OAuth2RefreshToken updateRefreshToken(OAuth2Authentication authentication,String ref_tokn) {
    if (!isSupportRefreshToken(authentication.getOAuth2Request())) {
        return null;
    }
    int validitySeconds = getRefreshTokenValiditySeconds(authentication.getOAuth2Request());
    String value = ref_tokn;
    if (validitySeconds > 0) {
        return new DefaultExpiringOAuth2RefreshToken(value, new Date(System.currentTimeMillis()
                + (validitySeconds * 1000L)));
    }
    return new DefaultOAuth2RefreshToken(value);
}

private OAuth2AccessToken createAccessToken(OAuth2Authentication authentication, OAuth2RefreshToken refreshToken) {
    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(refreshToken);
    token.setScope(authentication.getOAuth2Request().getScope());

    return accessTokenEnhancer != null ? accessTokenEnhancer.enhance(token, authentication) : token;
}

/**
 * The access token validity period in seconds
 * 
 * @param clientAuth the current authorization request
 * @return the access token validity period in seconds
 */
protected int getAccessTokenValiditySeconds(OAuth2Request clientAuth) {
    if (clientDetailsService != null) {
        ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
        Integer validity = client.getAccessTokenValiditySeconds();
        if (validity != null) {
            return validity;
        }
    }
    return accessTokenValiditySeconds;
}

/**
 * The refresh token validity period in seconds
 * 
 * @param clientAuth the current authorization request
 * @return the refresh token validity period in seconds
 */
protected int getRefreshTokenValiditySeconds(OAuth2Request clientAuth) {
    if (clientDetailsService != null) {
        ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
        Integer validity = client.getRefreshTokenValiditySeconds();
        if (validity != null) {
            return validity;
        }
    }
    return refreshTokenValiditySeconds;
}

/**
 * Is a refresh token supported for this client (or the global setting if
 * {@link #setClientDetailsService(ClientDetailsService) clientDetailsService} is not set.
 * 
 * @param clientAuth the current authorization request
 * @return boolean to indicate if refresh token is supported
 */
protected boolean isSupportRefreshToken(OAuth2Request clientAuth) {
    if (clientDetailsService != null) {
        ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
        return client.getAuthorizedGrantTypes().contains("refresh_token");
    }
    return this.supportRefreshToken;
}

/**
 * An access token enhancer that will be applied to a new token before it is saved in the token store.
 * 
 * @param accessTokenEnhancer the access token enhancer to set
 */
public void setTokenEnhancer(TokenEnhancer accessTokenEnhancer) {
    this.accessTokenEnhancer = accessTokenEnhancer;
}

/**
 * The validity (in seconds) of the refresh token. If less than or equal to zero then the tokens will be
 * non-expiring.
 * 
 * @param refreshTokenValiditySeconds The validity (in seconds) of the refresh token.
 */
public void setRefreshTokenValiditySeconds(int refreshTokenValiditySeconds) {
    this.refreshTokenValiditySeconds = refreshTokenValiditySeconds;
}

/**
 * The default validity (in seconds) of the access token. Zero or negative for non-expiring tokens. If a client
 * details service is set the validity period will be read from he client, defaulting to this value if not defined
 * by the client.
 * 
 * @param accessTokenValiditySeconds The validity (in seconds) of the access token.
 */
public void setAccessTokenValiditySeconds(int accessTokenValiditySeconds) {
    this.accessTokenValiditySeconds = accessTokenValiditySeconds;
}

/**
 * Whether to support the refresh token.
 * 
 * @param supportRefreshToken Whether to support the refresh token.
 */
public void setSupportRefreshToken(boolean supportRefreshToken) {
    this.supportRefreshToken = supportRefreshToken;
}

/**
 * Whether to reuse refresh tokens (until expired).
 * 
 * @param reuseRefreshToken Whether to reuse refresh tokens (until expired).
 */
public void setReuseRefreshToken(boolean reuseRefreshToken) {
    this.reuseRefreshToken = reuseRefreshToken;
}

/**
 * The persistence strategy for token storage.
 * 
 * @param tokenStore the store for access and refresh tokens.
 */
public void setTokenStore(TokenStore tokenStore) {
    this.tokenStore = tokenStore;
}

/**
 * An authentication manager that will be used (if provided) to check the user authentication when a token is
 * refreshed.
 * 
 * @param authenticationManager the authenticationManager to set
 */
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
    this.authenticationManager = authenticationManager;
}

/**
 * The client details service to use for looking up clients (if necessary). Optional if the access token expiry is
 * set globally via {@link #setAccessTokenValiditySeconds(int)}.
 * 
 * @param clientDetailsService the client details service
 */
public void setClientDetailsService(ClientDetailsService clientDetailsService) {
    this.clientDetailsService = clientDetailsService;
}

}