美文网首页Oauth2tokenJavaWeb 知识点
OAuth2.0关于刷新token的问题

OAuth2.0关于刷新token的问题

作者: 花荣贤弟 | 来源:发表于2018-10-08 20:25 被阅读412次

    通过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<TokenEnhancer> 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<TokenEnhancer> 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<String, Object> info = new LinkedHashMap<String, Object>(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<String, Object> claims = objectMapper
                            .parseMap(JwtHelper.decode(refreshToken.getValue()).getClaims());
                    if (claims.containsKey(TOKEN_ID)) {
                        encodedRefreshToken.setValue(claims.get(TOKEN_ID).toString());
                    }
                }
                catch (IllegalArgumentException e) {
                }
                Map<String, Object> refreshTokenInfo = new LinkedHashMap<String, Object>(
                        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的问题

        本文链接:https://www.haomeiwen.com/subject/ffajaftx.html