• 在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






  • 相关阅读:
    字符串的不可变性--转载
    this的作用--转载
    构造函数
    根基决定一个程序员会不会被淘汰 --转载
    BAT-使用BAT方法清理Delphi临时文件
    键盘,鼠标,文件
    画布.画笔.画刷
    Delphi外挂开发网站
    教程-经典Delphi教程网
    教程-Delphi各版本与工具下载地址
  • 原文地址:https://www.cnblogs.com/panchanggui/p/12395451.html
Copyright © 2020-2023  润新知