content: package openjoe.smart.sso.server.manager.local;
  
  import openjoe.smart.sso.base.entity.ExpirationPolicy;
  import openjoe.smart.sso.base.entity.ExpirationWrapper;
  import openjoe.smart.sso.server.entity.TokenContent;
  import openjoe.smart.sso.server.manager.AbstractTokenManager;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  import org.springframework.util.CollectionUtils;
  
  import java.util.*;
  import java.util.concurrent.ConcurrentHashMap;
  
  /**
   * 本地调用凭证管理
   *
   * @author Joe
   */
  public class LocalTokenManager extends AbstractTokenManager implements ExpirationPolicy {
  
      private final Logger logger = LoggerFactory.getLogger(LocalTokenManager.class);
      private Map<String, ExpirationWrapper<String>> accessTokenMap = new ConcurrentHashMap<>();
      private Map<String, ExpirationWrapper<TokenContent>> refreshTokenMap = new ConcurrentHashMap<>();
      private Map<String, Set<String>> tgtMap = new ConcurrentHashMap<>();
  
      public LocalTokenManager(int accessTokenTimeout, int refreshTokenTimeout, int threadPoolSize) {
          super(accessTokenTimeout, refreshTokenTimeout, threadPoolSize);
      }
  
      @Override
      public void create(String refreshToken, TokenContent tokenContent) {
          ExpirationWrapper<String> atWrapper = new ExpirationWrapper(refreshToken, getAccessTokenTimeout());
          accessTokenMap.put(tokenContent.getAccessToken(), atWrapper);
  
          ExpirationWrapper<TokenContent> rtWrapper = new ExpirationWrapper(tokenContent, getRefreshTokenTimeout());
          refreshTokenMap.put(refreshToken, rtWrapper);
  
          tgtMap.computeIfAbsent(tokenContent.getTgt(), a -> new HashSet<>()).add(refreshToken);
          logger.debug("调用凭证创建成功, accessToken:{}, refreshToken:{}", tokenContent.getAccessToken(), refreshToken);
      }
  
      @Override
      public TokenContent get(String refreshToken) {
          ExpirationWrapper<TokenContent> wrapper = refreshTokenMap.get(refreshToken);
          if (wrapper == null || wrapper.checkExpired()) {
              return null;
          } else {
              return wrapper.getObject();
          }
      }
  
      @Override
      public TokenContent getByAccessToken(String accessToken) {
          ExpirationWrapper<String> wrapper = accessTokenMap.get(accessToken);
          if (wrapper == null || wrapper.checkExpired()) {
              return null;
          }
          return get(wrapper.getObject());
      }
  
      @Override
      public void remove(String refreshToken) {
          // 删除refreshToken
          ExpirationWrapper<TokenContent> wrapper = refreshTokenMap.remove(refreshToken);
          if (wrapper == null) {
              return;
          }
  
          // 删除accessToken
          accessTokenMap.remove(wrapper.getObject().getAccessToken());
  
          // 删除tgt映射中的refreshToken
          Set<String> refreshTokenSet = tgtMap.get(wrapper.getObject().getTgt());
          if (CollectionUtils.isEmpty(refreshTokenSet)) {
              return;
          }
          refreshTokenSet.remove(refreshToken);
      }
  
      @Override
      public void removeByTgt(String tgt) {
          // 删除tgt映射中的refreshToken集合
          Set<String> refreshTokenSet = tgtMap.remove(tgt);
          if (CollectionUtils.isEmpty(refreshTokenSet)) {
              return;
          }
          submitRemoveToken(refreshTokenSet);
      }
  
      @Override
      public void processRemoveToken(String refreshToken) {
          // 删除refreshToken
          ExpirationWrapper<TokenContent> wrapper = refreshTokenMap.remove(refreshToken);
          if (wrapper == null) {
              return;
          }
          TokenContent tokenContent = wrapper.getObject();
          if (tokenContent == null) {
              return;
          }
  
          // 删除accessToken
          accessTokenMap.remove(tokenContent.getAccessToken());
  
          // 发起客户端退出请求
          logger.debug("发起客户端退出请求, accessToken:{}, refreshToken:{}, logoutUri:{}", tokenContent.getAccessToken(), refreshToken, tokenContent.getLogoutUri());
          sendLogoutRequest(tokenContent.getLogoutUri(), tokenContent.getAccessToken());
      }
  
      @Override
      public Map<String, Set<String>> getClientIdMapByTgt(Set<String> tgtSet) {
          Map<String, Set<String>> clientIdMap = new HashMap<>();
          tgtSet.forEach(tgt -> {
              Set<String> refreshTokenSet = tgtMap.get(tgt);
              Set<String> clientIdSet = new HashSet<>();
              refreshTokenSet.forEach(refreshToken -> {
                  ExpirationWrapper<TokenContent> wrapper = refreshTokenMap.get(refreshToken);
                  if (wrapper == null) {
                      return;
                  }
                  TokenContent tokenContent = wrapper.getObject();
                  if (tokenContent == null) {
                      return;
                  }
                  clientIdSet.add(tokenContent.getClientId());
              });
              clientIdMap.put(tgt, clientIdSet);
          });
          return clientIdMap;
      }
  
      @Override
      public void verifyExpired() {
          accessTokenMap.forEach((accessToken, wrapper) -> {
              if (wrapper.checkExpired()) {
                  accessTokenMap.remove(accessToken);
                  logger.debug("调用凭证已失效, accessToken:{}", accessToken);
              }
          });
  
          refreshTokenMap.forEach((refreshToken, wrapper) -> {
              if (wrapper.checkExpired()) {
                  remove(refreshToken);
                  logger.debug("刷新凭证已失效, accessToken:{}, refreshToken:{}", wrapper.getObject().getAccessToken(), refreshToken);
              }
          });
      }
  }
  