• SpringCloud中利用OAuth2实现客户端单设备登录


    在OAuth2生成Token的地方,源码里面会判断Token是否已经存在,如果存在且未过期直接返回旧的Token,如果不存在或已过期,则重新生成一个新的Token

    这里做一个改动:不管旧Token是否过期,都重新生成一个新的Token,保证在新客户端登录后,旧客户端上保存的Token立即失效

    具体实现:

    1、重新实现DefaultTokenServices的createAccessToken方法

    import java.util.Date;
    import java.util.UUID;
    
    import org.springframework.security.core.AuthenticationException;
    import org.springframework.security.oauth2.common.DefaultExpiringOAuth2RefreshToken;
    import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
    import org.springframework.security.oauth2.common.DefaultOAuth2RefreshToken;
    import org.springframework.security.oauth2.common.ExpiringOAuth2RefreshToken;
    import org.springframework.security.oauth2.common.OAuth2AccessToken;
    import org.springframework.security.oauth2.common.OAuth2RefreshToken;
    import org.springframework.security.oauth2.provider.OAuth2Authentication;
    import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
    import org.springframework.security.oauth2.provider.token.TokenEnhancer;
    import org.springframework.security.oauth2.provider.token.TokenStore;
    import org.springframework.transaction.annotation.Transactional;
    
    public class MyTokenServices extends DefaultTokenServices {
    
        private TokenStore    tokenStore;
        private TokenEnhancer accessTokenEnhancer;
    
        @Override
        public void setTokenStore(TokenStore tokenStore) {
            this.tokenStore = tokenStore;
        }
    
        @Override
        public void setTokenEnhancer(TokenEnhancer accessTokenEnhancer) {
            this.accessTokenEnhancer = accessTokenEnhancer;
        }
    
        @Override
        @Transactional
        public OAuth2AccessToken createAccessToken(OAuth2Authentication authentication) throws AuthenticationException {
            OAuth2AccessToken existingAccessToken = tokenStore.getAccessToken(authentication);
            OAuth2RefreshToken refreshToken = null;
            if (existingAccessToken != null) {
                //AccessToken存在,删除并重新创建,实现客户端单点登录功能
                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);
            }
    
            // 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;
    
        }
    
        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 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;
        }
    
    }
    

    2、在AuthorizationServerConfigurerAdapter中进行配置

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
    	//使用自定义的TokenServices
    	MyTokenServices tokenServices = new MyTokenServices();
    	tokenServices.setTokenStore(endpoints.getTokenStore());
    	// 这里如果设置为false则不能更新refresh_token,如果需要刷新token的功能需要设置成true
    	tokenServices.setSupportRefreshToken(false);
    	// 设置上次RefreshToken是否还可以使用 默认为true
    	tokenServices.setReuseRefreshToken(false);
    	tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
    	tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
    
    	endpoints.tokenServices(tokenServices);
    }
    

      

  • 相关阅读:
    luogu P1353 [USACO08JAN]跑步Running
    bzoj 2002: [Hnoi2010]Bounce 弹飞绵羊
    [USACO3.2]Sweet Butter
    [SDOI2009]Elaxia的路线
    [USACO5.4]Telecowmunication
    [洛谷1681]最大正方形II
    [清华集训2014]奇数国
    [洛谷2814]家谱
    [洛谷1868]饥饿的奶牛
    [HNOI2003]激光炸弹
  • 原文地址:https://www.cnblogs.com/voyager-fu/p/oauth2_single_device_login.html
Copyright © 2020-2023  润新知