OAuth2.0关于刷新token的问题

通过refresh token刷新access token时,refresh token也随之更新的问题?

项目背景:项目中使用SpringBoot集成OAuth2.0,实现对token的管理,此处包含两种token类型,refresh token和access token,两者都具有有效期,在OAuth的设计模式中往往refresh token的有效期都比较长(一般设置7天),而access token的有效期相对较短(一般为数个小时)。所以在具体的实施过程中,当access token过期而refresh token有效的时候,使用后者重新获取新的access token。

问题描述:最近在使用UAA开源项目时,发现每次使用refresh token刷新access token的时候,不光access token更新了,refresh token 同样也更新了,深究了UAA和OAuth的源码发现出现这种现象的原因由以下两点。

  1. 在UAA开源项目中,refresh token有两者使用模式:重复使用和非重复使用。
    所谓重复使用指的是登陆后初次生成的refresh token一直保持不变,直到过期;
    非重复使用指的是在每一次使用refresh token刷新access token的过程中,refresh token也随之更新,即生成新的refresh token。

  2. 在UAA项目中这一设置是通过UaaConfiguration类reuseRefreshTokens(boolean b)(默认为true)来设置完成;
    下面是代码重现的结果分析:

  3. 首先分析refresh token重复使用的情况,即在UaaConfiguration设置如下:

包名:com.yourcompany.uaa.config,类名:UaaConfiguration

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    Collection tokenEnhancers = applicationContext.getBeansOfType(TokenEnhancer.class).values();
    TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
    tokenEnhancerChain.setTokenEnhancers(new ArrayList<>(tokenEnhancers));
    endpoints
        .authenticationManager(authenticationManager)
        .tokenStore(tokenStore())
        .tokenEnhancer(tokenEnhancerChain)
         //该字段设置设置refresh token是否重复使用,true:reuse;false:no reuse.
        .reuseRefreshTokens(true);            
    }

用户登陆获取:同时获取access token 和 refresh token
access token:

access token: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbIm9wZW5pZCJdLCJleHAiOjE1MzkwMDEwNTksImlhdCI6MTUzOTAwMDk2OSwiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiIsIlJPTEVfVVNFUiJdLCJqdGkiOiI2YTY3YTQzNC0xNTk2LTQ3YTYtYTNmNS0zZmNjZTljOTJkMjQiLCJjbGllbnRfaWQiOiJ3ZWJfYXBwIn0.ZRSqW7aq3Zph04IuBKGlpyLBeMMf_vZZn8Ac50mJeUZpeWLYr_Mz3cXd0Zlp2DHMRZcpheZQhuqWCa4AaWkTOPuIaeVH-Gpooh_lwO3LPA93sqb4jwdBUoD0A62C4roo71Sz50Fc2WNo0h9t_XSO2L-tS6zFWoxLhqYkVhR_HpGTW_6h0VWixgik8W0lsU4h3oYLfI8G1cdAELtBHYB5n9YllDhEp4_ZXp1npr9UIsYKyJxXOAFBp_j1SBtoqu7fikA2zkIdVh54-EQRZozaII-LZwRpt5sLyCgSrs8eMMdW6ow_TSMyYWCovl5eaRZEv6-VW9XFH7QtORk1W-VjSw

使用jwt解析之后的对应的明文为:

{
  "user_name": "admin",
  "scope": [
    "openid"
  ],
  "exp": 1539001059,
  "iat": 1539000969,
  "authorities": [
    "ROLE_ADMIN",
    "ROLE_USER"
  ],
  "jti": "6a67a434-1596-47a6-a3f5-3fcce9c92d24",
  "client_id": "web_app"
}

refresh token:

refresh token: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbIm9wZW5pZCJdLCJhdGkiOiI2YTY3YTQzNC0xNTk2LTQ3YTYtYTNmNS0zZmNjZTljOTJkMjQiLCJleHAiOjE1MzkwMDQ1NjksImlhdCI6MTUzOTAwMDk2OSwiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiIsIlJPTEVfVVNFUiJdLCJqdGkiOiIxOTNhN2MyZC00Y2YxLTRhZjctODExOS0xZTljOWY5MTZiNmQiLCJjbGllbnRfaWQiOiJ3ZWJfYXBwIn0.XQsgqTkXqrS1X3u21tQqaHIvDZINcAtZ475kYSNikF7mFj8F91pyt9M6YRh9D_l0xmGqRPHldlwfMrxdQhSEir8WdrtfSOar9QpT4fZv9tyn9xPdKG5uq0jrtz2xq5ws17ZL-9PCFZJJnLQ6tLBXJ-hQnGEhA0Jq1JtCfpRIQ3VJM5561iN07yerjcIDfNLKQAGLd7I6Ilw_qRHDGeP0iZg5S-KPL-MApNwDfsxnHinRxeKUC2o2x0pJ8bhFKJQLIa-G4zKYrMhUc9bhzqMSERX3eJvsQldlr_6AoQgPokRTu0VHRa4Z7qOxTUC8hz2VDtxqOvzmQhrzeIyaSoLq1w

使用jwt解析之后的对应的明文为:

{
  "user_name": "admin",
  "scope": [
    "openid"
  ],
  "ati": "6a67a434-1596-47a6-a3f5-3fcce9c92d24",
  "exp": 1539004569,
  "iat": 1539000969,
  "authorities": [
    "ROLE_ADMIN",
    "ROLE_USER"
  ],
  "jti": "193a7c2d-4cf1-4af7-8119-1e9c9f916b6d",
  "client_id": "web_app"
}

待access token过期之后,执行刷新操作,重新获取如下access token 和 refresh token:
access token

access token: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbIm9wZW5pZCJdLCJleHAiOjE1MzkwMDExNTEsImlhdCI6MTUzOTAwMTA2MSwiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiIsIlJPTEVfVVNFUiJdLCJqdGkiOiI4ZDJkNjNhZS0wZmYwLTQ5OWEtODBhMy04ZTVhMTA0MTBmODMiLCJjbGllbnRfaWQiOiJ3ZWJfYXBwIn0.RFkfY_ghMt9Qh54HMjGWjzpJN1bRhsyMWiHlXPQ6vS1_KoKXyRD-Wvagqnd-cW_rH6ZuCqafGetJC5EcX7EClvAonP8o4vgK9CkidS68QBSbgm_yNqaBZDhbtq9sI0qMGDJ1U-YKjUtXOljIA7pxzdb0nqWJgYUanC4_X3snMUABpJTDBWouAUnk0L_V0gcSnX_qnaBxAg9hYG80T6F583tlCJDKawLGqZXdTpAm57ymoQKkkhXYvSvwKQ6DNcuJgZQSzpd5aAWvR_Sqs_BbqbhXlOZjjDO0caO5LqWGPLKfjBY8lFYrclr1-WG9WnDcOB5IlYKxZe27-sLE2yKBdw

解析之后明文:

{
  "user_name": "admin",
  "scope": [
    "openid"
  ],
  "exp": 1539001151,
  "iat": 1539001061,
  "authorities": [
    "ROLE_ADMIN",
    "ROLE_USER"
  ],
  "jti": "8d2d63ae-0ff0-499a-80a3-8e5a10410f83",
  "client_id": "web_app"
}

refrsh token:

refresh token:
 eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbIm9wZW5pZCJdLCJhdGkiOiI4ZDJkNjNhZS0wZmYwLTQ5OWEtODBhMy04ZTVhMTA0MTBmODMiLCJleHAiOjE1MzkwMDQ1NjksImlhdCI6MTUzOTAwMTA2MSwiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiIsIlJPTEVfVVNFUiJdLCJqdGkiOiIxOTNhN2MyZC00Y2YxLTRhZjctODExOS0xZTljOWY5MTZiNmQiLCJjbGllbnRfaWQiOiJ3ZWJfYXBwIn0.Mpw38-_isKhsXehUo7Fm3X3Sm6QvohIuq40ArTmfGkk2CEGNs7hyopJf17jjs2d3rCjNeiIcQqQKZPdIus0jrMv1X-dcxXxr_JFm0GgmVR0x-E2Gnva0XsNR2zVX8UddN885UCySCcVLuqdeMjxExf8ALzJNEtJvMiE11zug9FTSuXEZQCfbszHlVeoIVPLGQMK34c6XlqEbGLi9P4Z4QD5bptu5KU6f6Gf0ScoFISEXLBoAj7XKFQG86OjDamBJGZXgNw5R6RPU5qFS7SE_pfxenl_vCmcjvrTEfqsA98rCEGAfVCZyoF3Oj3S2uSkpQTaHo2UHLGY6Lr5ejwpbZw

解析之后明文:

{
  "user_name": "admin",
  "scope": [
    "openid"
  ],
  "ati": "8d2d63ae-0ff0-499a-80a3-8e5a10410f83",
  "exp": 1539004569,
  "iat": 1539001061,
  "authorities": [
    "ROLE_ADMIN",
    "ROLE_USER"
  ],
  "jti": "193a7c2d-4cf1-4af7-8119-1e9c9f916b6d",
  "client_id": "web_app"
}

结果分析:

通过对比refresh token刷新前后的明文信息可知,两个refresh token的jti(jwt-token-id,token的唯一属性)都为193a7c2d-4cf1-4af7-8119-1e9c9f916b6d,说明两个refresh token是同意个token,并为更新。心细的读者可能发现两个refresh token的加密字符串是不同的,其实这个原因是由于refresh token 中有个ati字段(access-token-id)信息,该字段是当前access token的唯一Id,由于access token更新了(由刷新前后access token的jti不同可证明),故而refresh token也相应作出改变,但是其过期时间等关键信息并未改变。这个也可以从下面的关键代码很明显的看出。
这种模式下的refresh token的过期仍然是以初次生成的时间为准。

  1. 现在介绍refresh token 非重复利用的场景:

非重复使用: 即当access token 更新的时候,同时更新refresh token,这样就把refresh token的过期时间一直往后延续。该模式的用意就是通过更新refresh token实现永远不需要再次登陆的目的。除非前后两次对项目的操作时间间隔超出了refresh token的有效时间段。

下面看一下演示效果,同样设置UaaConfiguration,

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    Collection tokenEnhancers = applicationContext.getBeansOfType(TokenEnhancer.class).values();
    TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
    tokenEnhancerChain.setTokenEnhancers(new ArrayList<>(tokenEnhancers));
    endpoints
        .authenticationManager(authenticationManager)
        .tokenStore(tokenStore())
        .tokenEnhancer(tokenEnhancerChain)
         //该字段设置设置refresh token是否重复使用,true:reuse;false:no reuse.
        .reuseRefreshTokens(false);            
    }

access token:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbIm9wZW5pZCJdLCJleHAiOjE1MzkwMDEzMzQsImlhdCI6MTUzOTAwMTI0NCwiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiIsIlJPTEVfVVNFUiJdLCJqdGkiOiI3NzM5NjdhZS01ODBkLTQzNTItYjQ1OS1jY2I5NWQyZWQyMGQiLCJjbGllbnRfaWQiOiJ3ZWJfYXBwIn0.Tag4FBZS2cj9RBnZaYkw3CbWD-3c-xDabMsf-j7fxr_p5LKDrMyq2rVUmdt_htQoHgDuawcot_m4z6FX6_1kk-592Y-rcxFPuRZ4Fma7kOLbUP8JSOWydNxIH0pPZsiFpKjUTICrFrYPQz_l_2xiPSl8iHBEGBWWYHYSFCu8krwP9pYTwJCXNaQ8fEpR9Gz4PouejWUwi4gOPPZoxZBnw_9YFd27Am2vOesghMphQHOIy65ClrGXLPxLe3hRg5WggPtKm1ekJmr5OyYH3V4NRowYQ8JeaPDA7peOcSK5IfrDcTqZS5veacR7elw0cjq0ykcWjyCDxbYqLE5INNjReg

解析后为:

{
  "user_name": "admin",
  "scope": [
    "openid"
  ],
  "exp": 1539001334,
  "iat": 1539001244,
  "authorities": [
    "ROLE_ADMIN",
    "ROLE_USER"
  ],
  "jti": "773967ae-580d-4352-b459-ccb95d2ed20d",
  "client_id": "web_app"
}

refresh token:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbIm9wZW5pZCJdLCJhdGkiOiI3NzM5NjdhZS01ODBkLTQzNTItYjQ1OS1jY2I5NWQyZWQyMGQiLCJleHAiOjE1MzkwMDQ4NDQsImlhdCI6MTUzOTAwMTI0NCwiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiIsIlJPTEVfVVNFUiJdLCJqdGkiOiIzMjZiMWRhNS0xYzc4LTQ5NTQtYTVmNC1lMDNlMTdmOTk5ZjMiLCJjbGllbnRfaWQiOiJ3ZWJfYXBwIn0.ScQBtEUMrKJKtFIZMuwkRGNyzRuZCkMJhHu1etwIEepUQ6RqB1EWejFRVRJGZoycMDKeNkMbB46dwOOP47NxQu5ITDBs5ccx7_7WlMD8z2JDVTpr9kRIXQBFMBHVH6VuZEmxIm2IGWn-qVWwLVUzP4xRiDEj8svXJD_J4gY4Yxrr1sT9C8NTFCN45EvfC2ELcR7tBSRs1iHLxdQCvKaEhmk22f006CbgKZp3CUj5nTV--8hIamF7xiNJ_P2p0jdURf5PMg_KDznEZsHnRRucfvQpT0jrxheGbngupVRqC5laTYmdGEac7J-eo_ONmKuxKoP_BgOChCY_IGhExX__zw

解析后为:

{
  "user_name": "admin",
  "scope": [
    "openid"
  ],
  "ati": "773967ae-580d-4352-b459-ccb95d2ed20d",
  "exp": 1539004844,
  "iat": 1539001244,
  "authorities": [
    "ROLE_ADMIN",
    "ROLE_USER"
  ],
  "jti": "326b1da5-1c78-4954-a5f4-e03e17f999f3",
  "client_id": "web_app"
}

待access token过期之后,执行刷新操作,重新获取如下access token 和 refresh token:
access token:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbIm9wZW5pZCJdLCJleHAiOjE1MzkwMDE0MzYsImlhdCI6MTUzOTAwMTM0NiwiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiIsIlJPTEVfVVNFUiJdLCJqdGkiOiJlYTJhZGRjZC1jN2VlLTQ0MWUtYTdiNi05ZTQ2NTc1MDJjZGUiLCJjbGllbnRfaWQiOiJ3ZWJfYXBwIn0.LUDpv6ZOwq4T1u9HUU1oB1-JeU6TsjXgA5mfBwNXi3GFt8NAJzGKyrZWjYWoc2ajmLyYebZTTtN4qsX3fLxQY-toIw_utUA9XeoQEu8wG9Od3xm-rFjrTzatfH1CZVGvXV4mSvsf9wdLteTqV2_Fk_CaCAW8ycOLrcC8q8-I3gS_NnfaC8M9HExwiU9PO4GaddEmqsnqQ9hG3T0MftIvxCeFXNknLgCkmCFxXFpfJdmOxesmi0HKq482fsfv-hQQUwhrSnMopr6_xnfHXcx24FuO56IPSOIRHwxELMPK4owsKSvx1X9gSG2AVnd8L6LOR_vCJgDgKgjS1TicmoFxCA

解析后为:

{
  "user_name": "admin",
  "scope": [
    "openid"
  ],
  "exp": 1539001334,
  "iat": 1539001244,
  "authorities": [
    "ROLE_ADMIN",
    "ROLE_USER"
  ],
  "jti": "773967ae-580d-4352-b459-ccb95d2ed20d",
  "client_id": "web_app"
}

refresh token:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbIm9wZW5pZCJdLCJhdGkiOiJlYTJhZGRjZC1jN2VlLTQ0MWUtYTdiNi05ZTQ2NTc1MDJjZGUiLCJleHAiOjE1MzkwMDQ5NDYsImlhdCI6MTUzOTAwMTM0NiwiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiIsIlJPTEVfVVNFUiJdLCJqdGkiOiJhNzUzZTYyNS00NzVmLTQ0N2QtYmVhMC0xNWIxZmJmMTI5OWQiLCJjbGllbnRfaWQiOiJ3ZWJfYXBwIn0.EQjamSqLiEg4-LTWcTUC1vNl9xr_B0n40RE-rDMMTKzwp_TJcJpa4WXRmJ0cqvejY7q-SdBOahkSqTsOA7HYtlnhrXo12QYqKWa12lgJ7dOBO4hdW0LS1-MRFBKAlXXG-I-hjrupVjDW0fBoBWVEmKtpfarp3gCPEKFBsJD75ZRlP_IDluN3Rw1zS1WqvtJ0rLT70Uijyf1c9S6On4KVPRRzI-6_jG9pA3E3PAE4fWGOw0FOljeomlhBU1IFROfcXWvJkDYOOrfGo1rOGaSAaTZ8FTi_9pamF2QSoo1zbVD1xWEFwT-ZKJ7yC2xCjrWmYthZy03clG1kA_3XY25y3w

解析后:

{
  "user_name": "admin",
  "scope": [
    "openid"
  ],
  "ati": "ea2addcd-c7ee-441e-a7b6-9e4657502cde",
  "exp": 1539004946,
  "iat": 1539001346,
  "authorities": [
    "ROLE_ADMIN",
    "ROLE_USER"
  ],
  "jti": "a753e625-475f-447d-bea0-15b1fbf1299d",
  "client_id": "web_app"
}

结果分析:通过刷新前后refresh token的jti不一致不难看出,refresh token也已随着access token发生了更新。已经变成了两个不同的refresh token了,同时refresh token的过期时间也在一直往后延续,不在是初次生成refresh token时的过期时间了。
所以,在这种模式下,只要在refresh token有效期内执行操作,用户无需再次登陆。

关键代码:

包名 org.springframework.security.oauth2.provider.token.store 类名:JwtAccessTokenConverter 类

    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
        DefaultOAuth2AccessToken result = new DefaultOAuth2AccessToken(accessToken);
        Map info = new LinkedHashMap(accessToken.getAdditionalInformation());
        String tokenId = result.getValue();
        if (!info.containsKey(TOKEN_ID)) {
            info.put(TOKEN_ID, tokenId);
        }
        else {
            tokenId = (String) info.get(TOKEN_ID);
        }
        result.setAdditionalInformation(info);
        result.setValue(encode(result, authentication));
        OAuth2RefreshToken refreshToken = result.getRefreshToken();
        if (refreshToken != null) {
            DefaultOAuth2AccessToken encodedRefreshToken = new DefaultOAuth2AccessToken(accessToken);
            encodedRefreshToken.setValue(refreshToken.getValue());
            // Refresh tokens do not expire unless explicitly of the right type
            encodedRefreshToken.setExpiration(null);
            try {
                Map claims = objectMapper
                        .parseMap(JwtHelper.decode(refreshToken.getValue()).getClaims());
                if (claims.containsKey(TOKEN_ID)) {
                    encodedRefreshToken.setValue(claims.get(TOKEN_ID).toString());
                }
            }
            catch (IllegalArgumentException e) {
            }
            Map refreshTokenInfo = new LinkedHashMap(
                    accessToken.getAdditionalInformation());
            refreshTokenInfo.put(TOKEN_ID, encodedRefreshToken.getValue());
            refreshTokenInfo.put(ACCESS_TOKEN_ID, tokenId);
            encodedRefreshToken.setAdditionalInformation(refreshTokenInfo);
            DefaultOAuth2RefreshToken token = new DefaultOAuth2RefreshToken(
                    encode(encodedRefreshToken, authentication));
            if (refreshToken instanceof ExpiringOAuth2RefreshToken) {
                Date expiration = ((ExpiringOAuth2RefreshToken) refreshToken).getExpiration();
                encodedRefreshToken.setExpiration(expiration);
                token = new DefaultExpiringOAuth2RefreshToken(encode(encodedRefreshToken, authentication), expiration);
            }
            result.setRefreshToken(token);
        }
        return result;
    }

包名 org.springframework.security.oauth2.provider.token ;类名:DefaultTokenServices类

@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);
        }
        OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken);
        tokenStore.storeAccessToken(accessToken, authentication);
        if (!reuseRefreshToken) {
            tokenStore.storeRefreshToken(accessToken.getRefreshToken(), authentication);
        }
        return accessToken;
    }

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

    }

从上面的源码可以分析,在refreshAccessToken()方法中,代码在询问refresh token是否需要重新生成;
在enhance()方法中,代码在给refresh token添加access token关联信息ati,让后再次加密。

你可能感兴趣的:(OAuth2.0关于刷新token的问题)