spring sercurity+redis實現每次登陸生成不同的token


在實際開發中,使用spring sercurity+redis生成並保存token會出現,不同客戶端使用的時同一個token(都是存儲在redis中),這將造成,其中一個客戶端注銷,

其他客戶端也被注銷了,極大的影響了開發效率,於是通過閱讀源碼,對token的生成做了修改,實現了每次登陸都是新的token。

參考地址:https://blog.csdn.net/gangsijay888/article/details/81977796

1、DefaultTokenServices

DefaultTokenServices類的createAccessToken方法將會通過當前登陸的用戶信息從redis中獲取token,若存在,則直接返回,否則生成新的。

 1 @Transactional
 2     public OAuth2AccessToken createAccessToken(OAuth2Authentication authentication) throws AuthenticationException {
 3                 //從redis中獲取登陸信息
 4         OAuth2AccessToken existingAccessToken = tokenStore.getAccessToken(authentication);
 5         OAuth2RefreshToken refreshToken = null;
 6         if (existingAccessToken != null) {
 7             if (existingAccessToken.isExpired()) {
 8                 if (existingAccessToken.getRefreshToken() != null) {
 9                     refreshToken = existingAccessToken.getRefreshToken();
10                     // The token store could remove the refresh token when the
11                     // access token is removed, but we want to
12                     // be sure...
13                     tokenStore.removeRefreshToken(refreshToken);
14                 }
15                 tokenStore.removeAccessToken(existingAccessToken);
16             }
17             else {
18                 // Re-store the access token in case the authentication has changed
19                 tokenStore.storeAccessToken(existingAccessToken, authentication);
20                 return existingAccessToken;
21             }
22         }
23 
24         // Only create a new refresh token if there wasn't an existing one
25         // associated with an expired access token.
26         // Clients might be holding existing refresh tokens, so we re-use it in
27         // the case that the old access token
28         // expired.
29         if (refreshToken == null) {
30             refreshToken = createRefreshToken(authentication);
31         }
32         // But the refresh token itself might need to be re-issued if it has
33         // expired.
34         else if (refreshToken instanceof ExpiringOAuth2RefreshToken) {
35             ExpiringOAuth2RefreshToken expiring = (ExpiringOAuth2RefreshToken) refreshToken;
36             if (System.currentTimeMillis() > expiring.getExpiration().getTime()) {
37                 refreshToken = createRefreshToken(authentication);
38             }
39         }
40 
41         OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken);
42         tokenStore.storeAccessToken(accessToken, authentication);
43         // In case it was modified
44         refreshToken = accessToken.getRefreshToken();
45         if (refreshToken != null) {
46             tokenStore.storeRefreshToken(refreshToken, authentication);
47         }
48         return accessToken;
49 
50     }    
View Code

2、RedisTokenStore

 1 @Override
 2     public OAuth2AccessToken getAccessToken(OAuth2Authentication authentication) {
 3               //根據登陸時的用戶信息並按照一定規則生成key,然后通過key從Reid是中獲取 
 4              //數據
 5         String key = authenticationKeyGenerator.extractKey(authentication);
 6         byte[] serializedKey = serializeKey(AUTH_TO_ACCESS + key);
 7         byte[] bytes = null;
 8         RedisConnection conn = getConnection();
 9         try {
10             bytes = conn.get(serializedKey);
11         } finally {
12             conn.close();
13         }
14         OAuth2AccessToken accessToken = deserializeAccessToken(bytes);
15         if (accessToken != null) {
16             OAuth2Authentication storedAuthentication = readAuthentication(accessToken.getValue());
17             if ((storedAuthentication == null || !key.equals(authenticationKeyGenerator.extractKey(storedAuthentication)))) {
18                 // Keep the stores consistent (maybe the same user is
19                 // represented by this authentication but the details have
20                 // changed)
21                 storeAccessToken(accessToken, authentication);
22             }
23 
24         }
25         return accessToken;
26     }
View Code

3、自定義key的生成規則

通過自定義key的生成規則,實現每次登陸都生成新的token。

 1 public class MyAuthenticationKeyGenerator extends DefaultAuthenticationKeyGenerator {
 2 
 3     private static final String CLIENT_ID = "client_id";
 4 
 5     private static final String SCOPE = "scope";
 6 
 7     private static final String USERNAME = "username";
 8 
 9     @Override
10     public String extractKey(OAuth2Authentication authentication) {
11         Map<String, String> values = new LinkedHashMap<String, String>();
12         OAuth2Request authorizationRequest = authentication.getOAuth2Request();
13         if (!authentication.isClientOnly()) {
14             //在用戶名后面添加時間戳,使每次的key都不一樣
15             values.put(USERNAME, authentication.getName()+System.currentTimeMillis());
16         }
17         values.put(CLIENT_ID, authorizationRequest.getClientId());
18         if (authorizationRequest.getScope() != null) {
19             values.put(SCOPE, OAuth2Utils.formatParameterList(new TreeSet<String>(authorizationRequest.getScope())));
20         }
21         return generateKey(values);
22     }
23 }
View Code

4、將自定義的key生成規則注入到RedisTokenStore中

@Configuration public class MyTokenStoreConfig { //同一個賬戶是否每次登陸使用同一個token
    @Value("${token.oneAccount.onlyOne}") private boolean onlyOne; @Autowired private RedisConnectionFactory redisConnectionFactory; @Bean public TokenStore tokenStore() { RedisTokenStore redisTokenStore = new RedisTokenStore(redisConnectionFactory); if (!onlyOne){ redisTokenStore.setAuthenticationKeyGenerator(new MyAuthenticationKeyGenerator()); } return redisTokenStore; } }

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM