All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.dahuatech.icc.oauth.handle.TokenHandlerProcessor Maven / Gradle / Ivy

The newest version!
package com.dahuatech.icc.oauth.handle;

import com.dahuatech.hutool.core.thread.NamedThreadFactory;
import com.dahuatech.hutool.core.util.StrUtil;
import com.dahuatech.hutool.json.JSONObject;
import com.dahuatech.hutool.json.JSONUtil;
import com.dahuatech.hutool.log.Log;
import com.dahuatech.hutool.log.LogFactory;
import com.dahuatech.icc.common.ErrorConstants;
import com.dahuatech.icc.exception.ClientException;
import com.dahuatech.icc.oauth.constant.OauthConstant;
import com.dahuatech.icc.oauth.http.IccTokenResponse;
import com.dahuatech.icc.oauth.model.v202010.*;
import com.dahuatech.icc.oauth.profile.GrantType;
import com.dahuatech.icc.oauth.profile.IccProfile;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;

/**
 * 单例,获取access_token,刷新access_token,登录状态保活
 *
 * @author 232676
 * @since 1.0.0 2020-10-24 20:59:11
 */
public class TokenHandlerProcessor {
  private static final Log logger = LogFactory.get();

  /** access_token 首次获取状态 */
  private static final AtomicBoolean TOKEN_INITED = new AtomicBoolean(Boolean.FALSE);
  /** token刷新间隔 30s */
  private static final long FRESH_TOKEN_INTERVAL = 30 * 1000;
  /** 线程刷新token和保活 */
  private final ScheduledExecutorService REFRESH_TOKEN_SCHEDULED =
      newSingleThreadScheduledExecutor(new NamedThreadFactory("Icc-Refresh-Token-New", true));
  /** 密码和客户端认证存储Map */
  private final Map tokenMap = new ConcurrentHashMap<>();
  private final Map httpConfigMap = new ConcurrentHashMap<>();

  public Map getTokenMap() {
    return tokenMap;
  }
  /** 定时任务刷新token */
  private TokenHandlerProcessor() {
    REFRESH_TOKEN_SCHEDULED.scheduleWithFixedDelay(
        new Runnable() {
          @Override
          public void run() {
            try {
              refreshTokenAndKeepAlive();
            } catch (Throwable t) { // Defensive fault tolerance
              logger.error("Unexpected error occur at token refresh, cause: " + t.getMessage(), t);
            }
          }
        },
        FRESH_TOKEN_INTERVAL,
        FRESH_TOKEN_INTERVAL,
        TimeUnit.MILLISECONDS);
  }

  /**
   * 获取Token处理器实例
   *
   * @return Token处理器实例
   */
  public static synchronized TokenHandlerProcessor getInstance() {
    return SingletonHolder.INSTANCE;
  }

  /**
   * 根据配置信息获取ICC令牌
   *
   * @param oauthConfigBaseInfo 配置信息
   * @return ICC令牌
   */
  public synchronized IccTokenResponse.IccToken oauth(OauthConfigBaseInfo oauthConfigBaseInfo) {

    IccTokenResponse.IccToken token = null;
    try {
      token = OauthProcessor.getIntance().oauth(oauthConfigBaseInfo);
      httpConfigMap.put(getKey(oauthConfigBaseInfo), oauthConfigBaseInfo);//保存用户信息用于异常情况,重新获取token
      tokenMap.put(getKey(oauthConfigBaseInfo), token);//保存token用于刷新token
    } catch (ClientException e) {
      logger.error("get token failure");
    }
    return token;
  }

  /**
   * 从缓存获取token
   *
   * @param oauthConfigBaseInfo 用户配置信息
   * @return IccTokenResponse.IccToken
   */
  public IccTokenResponse.IccToken getTokenCache(OauthConfigBaseInfo oauthConfigBaseInfo) {
    if(REFRESH_TOKEN_SCHEDULED.isShutdown() || REFRESH_TOKEN_SCHEDULED.isTerminated()){
      logger.warn("定时任务进程异常关闭,重新加载");
      REFRESH_TOKEN_SCHEDULED.scheduleWithFixedDelay(
              new Runnable() {
                @Override
                public void run() {
                  try {
                    refreshTokenAndKeepAlive();
                  } catch (Throwable t) { // Defensive fault tolerance
                    logger.error("Unexpected error occur at token refresh, cause: " + t.getMessage(), t);
                  }
                }
              },
              FRESH_TOKEN_INTERVAL,
              FRESH_TOKEN_INTERVAL,
              TimeUnit.MILLISECONDS);
    }
    String key = getKey(oauthConfigBaseInfo);
    IccTokenResponse.IccToken token = tokenMap.get(key);
    Long currentTime = System.currentTimeMillis();
    if(token != null && token.getTtl() < currentTime){//说明token过期了
      logger.warn("[{}]的token已过期,清理token信息:{}",key, JSONUtil.toJsonStr(token));
      clearExpiredToken(oauthConfigBaseInfo);
      return null;
    }
    return tokenMap.get(key);
  }

  /**
   * 刷新token 并缓存
   *
   * @param key 授权类型
   * @param refreshToken 刷新fresh_token
   * @return IccTokenResponse.IccToken
   */
  public IccTokenResponse.IccToken refreshToken(String key, String refreshToken) {
    OauthConfigBaseInfo oauthConfigBaseInfo = httpConfigMap.get(key);
    try {
      if(oauthConfigBaseInfo.getGrantType() == GrantType.password){//用户密码模式刷新token
        OauthRefreshTokenResponse refreshTokenResponse = OauthProcessor.getIntance().refreshToken(oauthConfigBaseInfo,refreshToken);
        if (refreshTokenResponse.isSuccess()) {
          OauthRefreshTokenResponse.IccReFreshToken freshToken = refreshTokenResponse.getData();
          IccTokenResponse.IccToken iccToken = new IccTokenResponse.IccToken();
          iccToken.setTtl(System.currentTimeMillis() + (freshToken.getExpires_in() * 1000));
          iccToken.setAccess_token(freshToken.getAccess_token());
          iccToken.setExpires_in(freshToken.getExpires_in());
          iccToken.setMagicId(freshToken.getMagicId());
          iccToken.setUserId(freshToken.getUserId());
          iccToken.setToken_type(freshToken.getToken_type());
          iccToken.setRefresh_token(freshToken.getRefresh_token());
          iccToken.setScope(freshToken.getScope());
          tokenMap.put(getKey(oauthConfigBaseInfo),iccToken);//保存token用于刷新token
          return iccToken;
        }else{
          return oauth(oauthConfigBaseInfo);
        }
      }else if(oauthConfigBaseInfo.getGrantType() == GrantType.client_credentials){
        IccTokenResponse.IccToken refreshTokenResponse = OauthProcessor.getIntance().oauth(oauthConfigBaseInfo);
        tokenMap.put(getKey(oauthConfigBaseInfo),refreshTokenResponse);//保存token用于刷新token
        return refreshTokenResponse;
      }
    } catch (ClientException e) {
      logger.error(
          "fresh token error , grantType=[{}],freshToken=[{}]", oauthConfigBaseInfo.getGrantType().name(), refreshToken);
    }
    return null;
  }

  /**
   * 定期刷新和保持token有效性
   */
  private void refreshTokenAndKeepAlive() {
    for (Map.Entry entry : tokenMap.entrySet()) {
      IccTokenResponse.IccToken token = entry.getValue();
      Long currentTime = System.currentTimeMillis();
      /** 如果时间还剩120s,则刷新token */
      if (token.getTtl() - currentTime <= 120 * 1000) {
        refreshToken(entry.getKey(), token.getRefresh_token());
      }
      keepalive(entry.getKey());
    }
  }

  /** 保活接口 */
  private void keepalive(String key) {
    OauthConfigBaseInfo oauthConfigBaseInfo = httpConfigMap.get(key);
    IccTokenResponse.IccToken token = tokenMap.get(key);
    try {
      BrmKeepAliveResponse brmKeepAliveResponse = OauthProcessor.getIntance().keepAlive(oauthConfigBaseInfo,token.getMagicId(), OauthConstant.ClientType.WEB);
      if(!brmKeepAliveResponse.isSuccess() && ErrorConstants.OAUTH_INVALID_TOKEN.equalsIgnoreCase(
              brmKeepAliveResponse.getCode())){
        oauth(oauthConfigBaseInfo);
      }
    } catch (Exception e) {
      e.printStackTrace();
      try{
        oauth(oauthConfigBaseInfo);
      }catch (Exception retryE){
        logger.error("keepalive retry error,key:" + key,e);
      };
    }
  }

  /**
   * 根据授权类型获取授权密钥名称
   *
   * @param grantType 授权类型
   * @return 授权密钥名称
   */
  private String enGrantKeyName(String grantType) {
    return grantType + StrUtil.COLON + IccProfile.host;
  }

  /**
   * 根据授权密钥名称获取授权类型
   *
   * @param grantKeyName 授权密钥名称
   * @return 授权类型
   */
  private GrantType deGrantType(String grantKeyName) {
    return GrantType.valueOf(grantKeyName.substring(0, grantKeyName.indexOf(StrUtil.COLON)));
  }

  /**
   * 清除过期的token
   *
   * @param oauthConfigBaseInfo
   */
  public void clearExpiredToken(OauthConfigBaseInfo oauthConfigBaseInfo) {
    tokenMap.remove(getKey(oauthConfigBaseInfo));
    httpConfigMap.remove(getKey(oauthConfigBaseInfo));
  }

  private static class SingletonHolder {
    private static final TokenHandlerProcessor INSTANCE = new TokenHandlerProcessor();
  }

  /**
   * key 格式
   * @param oauthConfigBaseInfo
   * @return
   */
  private String getKey(OauthConfigBaseInfo oauthConfigBaseInfo){
    String host = oauthConfigBaseInfo.getHttpConfigInfo().getHost();
    String port = oauthConfigBaseInfo.getHttpConfigInfo().isEnableHttpTest()? oauthConfigBaseInfo.getHttpConfigInfo().getHttpPort():oauthConfigBaseInfo.getHttpConfigInfo().getHttpsPort();
    String grantType = oauthConfigBaseInfo.getGrantType().name();
    String userName = null;
    if(oauthConfigBaseInfo.getGrantType() == GrantType.password){
      OauthConfigUserPwdInfo oauthConfigUserPwdInfo = (OauthConfigUserPwdInfo)oauthConfigBaseInfo;
      userName = oauthConfigUserPwdInfo.getUsername();
    }else{
      OauthConfigClientInfo oauthConfigClientInfo = (OauthConfigClientInfo)oauthConfigBaseInfo;
      userName = oauthConfigClientInfo.getClientOauthuserId();
    }

    return host + "_" + port + "_" + grantType + "_" + userName;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy