redisTokenStore源码:
@Override
public void storeAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
byte[] serializedAccessToken = this.serialize((Object)token);
byte[] serializedAuth = this.serialize((Object)authentication);
byte[] accessKey = this.serializeKey("access:" + token.getValue());
byte[] authKey = this.serializeKey("auth:" + token.getValue());
byte[] authToAccessKey = this.serializeKey("auth_to_access:" + this.authenticationKeyGenerator.extractKey(authentication));
byte[] approvalKey = this.serializeKey("uname_to_access:" + getApprovalKey(authentication));
byte[] clientId = this.serializeKey("client_id_to_access:" + authentication.getOAuth2Request().getClientId());
System.out.println("clientId:"+"client_id_to_access:" + authentication.getOAuth2Request().getClientId());
RedisConnection conn = this.getConnection();
try {
conn.openPipeline();
conn.stringCommands().set(accessKey, serializedAccessToken);
conn.stringCommands().set(authKey, serializedAuth);
conn.stringCommands().set(authToAccessKey, serializedAccessToken);
if (!authentication.isClientOnly()) {
conn.rPush(approvalKey, new byte[][]{serializedAccessToken});
}
conn.rPush(clientId, new byte[][]{serializedAccessToken});
if (token.getExpiration() != null) {
int seconds = token.getExpiresIn();
conn.expire(accessKey, (long)seconds);
conn.expire(authKey, (long)seconds);
conn.expire(authToAccessKey, (long)seconds);
conn.expire(clientId, (long)seconds);
conn.expire(approvalKey, (long)seconds);
}
OAuth2RefreshToken refreshToken = token.getRefreshToken();
if (refreshToken != null && refreshToken.getValue() != null) {
byte[] refresh = this.serialize(token.getRefreshToken().getValue());
byte[] auth = this.serialize(token.getValue());
byte[] refreshToAccessKey = this.serializeKey("refresh_to_access:" + token.getRefreshToken().getValue());
conn.stringCommands().set(refreshToAccessKey, auth);
byte[] accessToRefreshKey = this.serializeKey("access_to_refresh:" + token.getValue());
conn.stringCommands().set(accessToRefreshKey, refresh);
if (refreshToken instanceof ExpiringOAuth2RefreshToken) {
ExpiringOAuth2RefreshToken expiringRefreshToken = (ExpiringOAuth2RefreshToken)refreshToken;
Date expiration = expiringRefreshToken.getExpiration();
if (expiration != null) {
int seconds = Long.valueOf((expiration.getTime() - System.currentTimeMillis()) / 1000L).intValue();
conn.expire(refreshToAccessKey, (long)seconds);
conn.expire(accessToRefreshKey, (long)seconds);
}
}
}
conn.closePipeline();
} finally {
conn.close();
}
}
产生问题:
uname_to_access和client_id_to_access在用户一直登录刷新时,这两个list将一直不会过期,只有调用removeAccessToken()时才会清除,
但是绝大多数accessToken都是自然过期的,并不会触发该方法,client_id_to_access主要用户存储、查找客户端登录的accessToken.
client_id_to_access设置的过期时间是对clientId,value仍然会一直存在,在一直登录的情况下clientId并不会过期,所以就会造成list一直增量存储,而不过期
2个处理办法:
1.删除client list的维护,如果要获取某个客户端的用户数量,需要模糊查询redis key
2.定时任务扫描client list中的token,删除过期的令牌
github其他人提的issue:
https://github.com/spring-projects/spring-security-oauth/issues/1657
当前处理办法:
删除client_id_to_access存储,uname_to_access将list改为key value