zoukankan      html  css  js  c++  java
  • oauth2中client_id_to_access数据膨胀问题

     


    这是删除后,过了一两天就增长到了4万多条数据了。

    查看了RedisTokenStore 发现token 会不断地往list塞值。

    public void storeAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
    byte[] serializedAccessToken = serialize(token);
    byte[] serializedAuth = serialize(authentication);
    byte[] accessKey = serializeKey(ACCESS + token.getValue());
    byte[] authKey = serializeKey(AUTH + token.getValue());
    byte[] authToAccessKey = serializeKey(AUTH_TO_ACCESS + authenticationKeyGenerator.extractKey(authentication));
    byte[] approvalKey = serializeKey(UNAME_TO_ACCESS + getApprovalKey(authentication));
    byte[] clientId = serializeKey(CLIENT_ID_TO_ACCESS + authentication.getOAuth2Request().getClientId());
    
    RedisConnection conn = getConnection();
    try {
    conn.openPipeline();
    if (springDataRedis_2_0) {
    try {
    this.redisConnectionSet_2_0.invoke(conn, accessKey, serializedAccessToken);
    this.redisConnectionSet_2_0.invoke(conn, authKey, serializedAuth);
    this.redisConnectionSet_2_0.invoke(conn, authToAccessKey, serializedAccessToken);
    } catch (Exception ex) {
    throw new RuntimeException(ex);
    }
    } else {
    conn.set(accessKey, serializedAccessToken);
    conn.set(authKey, serializedAuth);
    conn.set(authToAccessKey, serializedAccessToken);
    }
    if (!authentication.isClientOnly()) {
    conn.rPush(approvalKey, serializedAccessToken);
    }
    conn.rPush(clientId, serializedAccessToken);
    if (token.getExpiration() != null) {
    int seconds = token.getExpiresIn();
    conn.expire(accessKey, seconds);
    conn.expire(authKey, seconds);
    conn.expire(authToAccessKey, seconds);
    conn.expire(clientId, seconds);
    conn.expire(approvalKey, seconds);
    }
    OAuth2RefreshToken refreshToken = token.getRefreshToken();
    if (refreshToken != null && refreshToken.getValue() != null) {
    byte[] refresh = serialize(token.getRefreshToken().getValue());
    byte[] auth = serialize(token.getValue());
    byte[] refreshToAccessKey = serializeKey(REFRESH_TO_ACCESS + token.getRefreshToken().getValue());
    byte[] accessToRefreshKey = serializeKey(ACCESS_TO_REFRESH + token.getValue());
    if (springDataRedis_2_0) {
    try {
    this.redisConnectionSet_2_0.invoke(conn, refreshToAccessKey, auth);
    this.redisConnectionSet_2_0.invoke(conn, accessToRefreshKey, refresh);
    } catch (Exception ex) {
    throw new RuntimeException(ex);
    }
    } else {
    conn.set(refreshToAccessKey, auth);
    conn.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, seconds);
    conn.expire(accessToRefreshKey, seconds);
    }
    }
    }
    conn.closePipeline();
    } finally {
    conn.close();
    }
    }
     

    默认的实现方法 DefaultTokenServices,里面就写了如果失效了就会删除token,反之则不断塞值进去

    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 {
    // Re-store the access token in case the authentication has changed
    tokenStore.storeAccessToken(existingAccessToken, authentication);
    return 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;
    
    }
    

      

    了解到在使用redis存储token时,client_id_to_access这个key存储了每个clientId申请的OAuth2AccessToken的集合,方便用来审计和应急处理跟clientId相关的token

    查看RedisTokenStore代码,这是个set集合,每次生成token时会进行一次追加,导致数据急剧膨胀,redis空间不足,线上生产曾经遇到过最大达1.5G,且该key每次生成时会重置过期时间,导致永不删除。

    解决方案:
    1、直接删除该key,不影响token生成及checkToken;
    2、魔改RedisTokenStore实现,调整数据结构存储;
    3、过期时间设置不要过长,在登录最大间隔休息时间之内,这样不会因为重置过期时间一直导致数据不删除

  • 相关阅读:
    Python Module_subprocess_子进程(程序调用)
    开机自启动Powershell脚本
    开机自启动Powershell脚本
    Powershell 音乐播放
    Powershell 音乐播放
    Powershell指令集_2
    Zabbix实战-简易教程(1)--总流程
    AWS上获取监控数据(EC2/RDS都支持)
    Grafana最新版本4.3.1安装(后端使用mysql)
    Haproxy实战(3)
  • 原文地址:https://www.cnblogs.com/yuarvin/p/14814991.html
Copyright © 2011-2022 走看看