在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






posted @ 2020-03-02 14:22  panchanggui  阅读(2453)  评论(0编辑  收藏