content: package org.superboot.service.impl;
  
  import com.alibaba.fastjson.JSON;
  import com.alibaba.fastjson.JSONObject;
  import com.xiaoleilu.hutool.crypto.asymmetric.KeyType;
  import com.xiaoleilu.hutool.crypto.asymmetric.RSA;
  import com.xiaoleilu.hutool.lang.Base64;
  import com.xiaoleilu.hutool.util.CharsetUtil;
  import com.xiaoleilu.hutool.util.StrUtil;
  import org.apache.commons.lang.StringUtils;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.data.redis.core.ValueOperations;
  import org.springframework.stereotype.Service;
  import org.springframework.web.context.request.ServletRequestAttributes;
  import org.superboot.base.*;
  import org.superboot.common.pub.Pub_RedisUtils;
  import org.superboot.common.utils.JWT_Utils;
  import org.superboot.entity.request.LoginUser;
  import org.superboot.entity.request.RegisterUser;
  import org.superboot.entity.request.ReqOtherLogin;
  import org.superboot.entity.request.Token;
  import org.superboot.entity.response.ResToken;
  import org.superboot.remote.UserRemote;
  import org.superboot.service.PubService;
  import org.superboot.utils.AESUtil;
  
  import javax.servlet.http.HttpServletRequest;
  import java.util.HashMap;
  
  
  @Service
  public class PubServiceImpl extends BaseService implements PubService {
  
      @Autowired
      JWT_Utils jwtUtils;
  
      @Autowired
      UserRemote userRemote;
  
  
      @Autowired
      private Pub_RedisUtils redisUtils;
  
  
      /**
       * RSA解密
       *
       * @param text 密文
       * @return
       */
      private String rsaDecrypt(String text) throws Exception {
          //使用hutool进行RSA解密，这个的优势是免去使用第三方JAR包的依赖
          RSA rsa = new RSA(BaseConstants.DEFAULT_PKCS8_PRIVATE_KEY, BaseConstants.DEFAULT_PUBLIC_KEY);
          //URL转码
          return new String(rsa.decrypt(Base64.decode(text), KeyType.PrivateKey), CharsetUtil.UTF_8);
      }
  
      /**
       * 获取ASE密钥信息
       *
       * @return
       */
      private String getAesKey() {
          ServletRequestAttributes attributes = getServletRequestAttributes();
          HttpServletRequest request = attributes.getRequest();
          String secretKey = request.getHeader(BaseConstants.SECRET_KEY);
          if (StrUtil.isNotBlank(secretKey)) {
              //执行RSA解密
              try {
                  return rsaDecrypt(secretKey);
              } catch (Exception e) {
                  throw new BaseException(StatusCode.DECODE_FAIL);
              }
          }
  
          return null;
      }
  
      /**
       * 执行数据解密
       *
       * @param value 加密后内容
       * @return
       */
      public String aesDecrypt(String value) {
          String secretKey = getAesKey();
          if (null != secretKey) {
              //解密密文信息
              try {
                  String deValue = AESUtil.aesDecrypt(value, secretKey);
                  //临时过渡时期，前端出现的BUG因为部分数字未加密解密后为空串造成接口错误，后期前台改完后此处删除掉
                  if (StrUtil.isBlank(deValue) && !value.endsWith("=")) {
                      return value;
                  }
                  return deValue;
              } catch (Exception e) {
                  return value;
              }
          }
  
          return value;
      }
  
  
      /**
       * 设置用户相关信息
       *
       * @param baseToken 用户信息
       * @param token     token
       * @return
       */
      private ResToken genResToken(BaseToken baseToken, String token) {
          ResToken resToken = new ResToken();
          //设置TOKEN
          resToken.setToken(token);
  
          //用户账号
          resToken.setUserName(baseToken.getUserName());
  
          //设置用户主键
          resToken.setUserPk(baseToken.getUserId());
          //设置用户公司
          resToken.setGroupPk(baseToken.getPkGroup());
  
          //设置关联用户
          resToken.setPkEmp(baseToken.getPkEmp());
  
          //设置所属机构
          resToken.setPkOrg(baseToken.getPkOrg());
  
          //设置最后登陆日期
          resToken.setLoginDate(baseToken.getLoginDate());
  
          //设置最后登陆时间
          resToken.setLoginTime(baseToken.getLoginTime());
  
          //账号停用时间
          resToken.setEndTime(baseToken.getEndTime());
  
          //用户名称
          resToken.setFullName(baseToken.getFullName());
  
  
          //员工姓名
          resToken.setEmpName(baseToken.getEmpName());
  
          //机构名称
          resToken.setOrgName(baseToken.getOrgName());
  
          //职务名称
          resToken.setDutiesName(baseToken.getDutiesName());
  
  
          //设置户类型
  
          if (-1 == baseToken.getPkGroup()) {
              //如果包含系统管理员角色则为系统管理员
              if (-1 != baseToken.getUserRole().indexOf(BaseConstants.SYS_ADMIN_NAME)) {
                  resToken.setUserType(-1);
              }
              //其他情况为系统级操作用户比如运维 开发人员
              else {
                  resToken.setUserType(1);
              }
          } else {
              //如果包含组织管理员角色则为组织管理员
              if (-1 != baseToken.getUserRole().indexOf(BaseConstants.GROUP_ADMIN_NAME)) {
                  resToken.setUserType(0);
              }
              //如果包含开放注册角色则为公开注册用户
              else if (-1 != baseToken.getUserRole().indexOf(BaseConstants.PUB_USER_NAME)) {
                  resToken.setUserType(3);
              }
              //其他为组织授权用户
              else {
                  resToken.setUserType(2);
              }
          }
  
          return resToken;
      }
  
  
      @Override
      public BaseResponse login(LoginUser loginUser) {
  
          if (isAes()) {
              //执行数据解密
              loginUser.setPlatform(aesDecrypt(loginUser.getPlatform()));
              loginUser.setVersion(aesDecrypt(loginUser.getVersion()));
              loginUser.setUserCode(aesDecrypt(loginUser.getUserCode()));
              loginUser.setUserPassword(aesDecrypt(loginUser.getUserPassword()));
          }
  
  
          //调用用户中心服务获取登陆信息
          BaseResponse response = userRemote.login(loginUser);
          if (BaseStatus.OK.getCode() == response.getStatus()) {
              //判断数据状态
              if (StatusCode.OK.getCode() == response.getCode()) {
                  JSONObject data = (JSONObject) JSON.toJSON(response.getData());
                  BaseToken bt = JSON.toJavaObject(data, BaseToken.class);
  
                  //判断白名单，用户是否已经生成过TOKEN了，如果生成过则不再进行登陆操作
                  String token = getRedisUtils().getTokenAllow(bt.getUserId(), loginUser.getPlatform(), loginUser.getVersion());
                  if (null == token) {
                      //生成新的TOKEN
                      token = jwtUtils.generateToken(bt);
                      //登陆后将TOKEN信息放入缓存
                      getRedisUtils().setTokenInfo(token, bt);
                      getRedisUtils().setTokenAllow(bt.getUserId(), loginUser.getPlatform(), loginUser.getVersion(), token);
                  } else {
                      //判断TOKEN是否已经锁定了，如果锁定了则需要重新生成新的TOKEN给客户端
                      ValueOperations<String, HashMap> operations = getRedisUtils().getRedisTemplate().opsForValue();
                      boolean exists = getRedisUtils().getRedisTemplate().hasKey(token);
                      if (exists) {
                          HashMap tokenItem = operations.get(token);
                          //如果TOKEN已经锁定，则重新生成TOKEN信息
                          if (Pub_RedisUtils.TOKEN_STATUS_LOCKED.equals(tokenItem.get(Pub_RedisUtils.TOKEN_STATUS))) {
                              //生成新的TOKEN
                              token = jwtUtils.generateToken(bt);
                              //登陆后将TOKEN信息放入缓存
                              getRedisUtils().setTokenInfo(token, bt);
                              getRedisUtils().setTokenAllow(bt.getUserId(), loginUser.getPlatform(), loginUser.getVersion(), token);
                          }
                      }
                  }
  
                  return new BaseResponse(genResToken(bt, token));
              }
  
          }
          return response;
  
      }
  
      @Override
      public BaseResponse sso(ReqOtherLogin otherLogin) {
  
          if (isAes()) {
              //执行数据解密
              otherLogin.setPlatform(aesDecrypt(otherLogin.getPlatform()));
              otherLogin.setVersion(aesDecrypt(otherLogin.getVersion()));
              otherLogin.setUserKey(aesDecrypt(otherLogin.getUserKey()));
          }
  
  
          //调用用户中心服务获取登陆信息
          BaseResponse response = userRemote.sso(otherLogin);
          if (BaseStatus.OK.getCode() == response.getStatus()) {
              //判断数据状态
              if (StatusCode.OK.getCode() == response.getCode()) {
                  JSONObject data = (JSONObject) JSON.toJSON(response.getData());
                  BaseToken bt = JSON.toJavaObject(data, BaseToken.class);
  
                  //判断白名单，用户是否已经生成过TOKEN了，如果生成过则不再进行登陆操作
                  String token = getRedisUtils().getTokenAllow(bt.getUserId(), otherLogin.getPlatform(), otherLogin.getVersion());
                  if (null == token) {
                      //生成新的TOKEN
                      token = jwtUtils.generateToken(bt);
                      //登陆后将TOKEN信息放入缓存
                      getRedisUtils().setTokenInfo(token, bt);
                      getRedisUtils().setTokenAllow(bt.getUserId(), otherLogin.getPlatform(), otherLogin.getVersion(), token);
                  } else {
                      //判断TOKEN是否已经锁定了，如果锁定了则需要重新生成新的TOKEN给客户端
                      ValueOperations<String, HashMap> operations = getRedisUtils().getRedisTemplate().opsForValue();
                      boolean exists = getRedisUtils().getRedisTemplate().hasKey(token);
                      if (exists) {
                          HashMap tokenItem = operations.get(token);
                          //如果TOKEN已经锁定，则重新生成TOKEN信息
                          if (Pub_RedisUtils.TOKEN_STATUS_LOCKED.equals(tokenItem.get(Pub_RedisUtils.TOKEN_STATUS))) {
                              //生成新的TOKEN
                              token = jwtUtils.generateToken(bt);
                              //登陆后将TOKEN信息放入缓存
                              getRedisUtils().setTokenInfo(token, bt);
                              getRedisUtils().setTokenAllow(bt.getUserId(), otherLogin.getPlatform(), otherLogin.getVersion(), token);
                          }
                      }
                  }
  
                  return new BaseResponse(genResToken(bt, token));
              }
  
          }
          return response;
      }
  
      @Override
      public BaseResponse tokenInfo() {
  
          ServletRequestAttributes attributes = getServletRequestAttributes();
          HttpServletRequest request = attributes.getRequest();
  
          String token = request.getHeader(BaseConstants.TOKEN_KEY);
          if (StringUtils.isBlank(token)) {
              throw new BaseException(StatusCode.TOKEN_INVALID);
          }
  
          BaseToken baseToken = getBaseToken();
  
          return new BaseResponse(genResToken(baseToken, token));
      }
  
  
      /**
       * 数据是否进行加密，部分接口不允许不加密请求
       *
       * @return
       */
      private boolean isAes() {
          if (StrUtil.isBlank(getAesKey())) {
              return false;
          }
          return true;
      }
  
      @Override
      public BaseResponse logout(String token) {
  
          //获取用户信息
          BaseToken bt = getRedisUtils().getTokenInfo(token);
          //清理TOKEN白名单信息
          getRedisUtils().cleanTokenAllow(bt.getUserId(), token);
          //从Redis中清理TOKEN信息
          getRedisUtils().getRedisTemplate().delete(token);
  
          return new BaseResponse(StatusCode.OPERATION_SUCCESS);
      }
  
      @Override
      public BaseResponse register(RegisterUser registerUser) {
  
          if (!isAes()) {
              //执行数据解密
              registerUser.setPlatform(aesDecrypt(registerUser.getPlatform()));
              registerUser.setVersion(aesDecrypt(registerUser.getVersion()));
              registerUser.setUserCode(aesDecrypt(registerUser.getUserCode()));
              registerUser.setUserPassword(aesDecrypt(registerUser.getUserPassword()));
              registerUser.setUserEmail(aesDecrypt(registerUser.getUserEmail()));
              registerUser.setUserPhone(aesDecrypt(registerUser.getUserPhone()));
              registerUser.setUserName(aesDecrypt(registerUser.getUserName()));
              registerUser.setEndTime(aesDecrypt(registerUser.getEndTime()));
          }
  
  
          BaseResponse response = userRemote.addUser(registerUser);
          if (BaseStatus.OK.getCode() == response.getStatus()) {
              //判断数据状态
              if (StatusCode.ADD_SUCCESS.getCode() == response.getCode()) {
                  JSONObject data = (JSONObject) JSON.toJSON(response.getData());
                  BaseToken bt = JSON.toJavaObject(data, BaseToken.class);
  
                  //判断白名单，用户是否已经生成过TOKEN了，如果生成过则不再进行登陆操作
                  String token = getRedisUtils().getTokenAllow(bt.getUserId(), registerUser.getPlatform(), registerUser.getVersion());
                  if (null == token) {
                      //生成新的TOKEN
                      token = jwtUtils.generateToken(bt);
                      //登陆后将TOKEN信息放入缓存
                      getRedisUtils().setTokenInfo(token, bt);
                      getRedisUtils().setTokenAllow(bt.getUserId(), registerUser.getPlatform(), registerUser.getVersion(), token);
                  }
  
                  return new BaseResponse(StatusCode.ADD_SUCCESS, genResToken(bt, token));
              }
  
          }
          return response;
      }
  
  
      @Override
      public BaseResponse refresh(String token) {
          if (null == token) {
              throw new BaseException(StatusCode.TOKEN_NOT_FIND);
          }
          //刷新生成新的TOKEN
          String tokenStr = jwtUtils.refreshToken(token);
          if (null == tokenStr) {
              throw new BaseException(StatusCode.TOKEN_INVALID);
          }
          //根据老的TOKEN获取用户信息
          BaseToken baseToken = getRedisUtils().getTokenInfo(token);
  
          //判断白名单，用户是否已经生成过TOKEN了，如果生成过则不再进行登陆操作
          HashMap<String, String> tokenItem = getRedisUtils().getTokenAllowItem(baseToken.getUserId(), token);
          if (null == token) {
              throw new BaseException(StatusCode.TOKEN_INVALID);
          } else {
              String version = tokenItem.get(BaseConstants.TOKEN_VERSION);
              String platform = tokenItem.get(BaseConstants.TOKEN_PLATFORM);
              //清理TOKEN
              getRedisUtils().cleanTokenAllow(baseToken.getUserId(), token);
              //从Redis中清理TOKEN信息
              getRedisUtils().getRedisTemplate().delete(token);
              //更新缓存信息
              getRedisUtils().setTokenInfo(tokenStr, baseToken);
              //更新新的TOKEN到白名单
              getRedisUtils().setTokenAllow(baseToken.getUserId(), platform, version, tokenStr);
  
          }
          return new BaseResponse(genResToken(baseToken, tokenStr));
      }
  
      @Override
      public BaseResponse locked(Token oldToken) {
  
          getRedisUtils().tokenLocked(oldToken.getToken(), true);
          return new BaseResponse(StatusCode.LOCKED_SUCCESS);
      }
  
      @Override
      public BaseResponse unLocked(Token oldToken) {
          getRedisUtils().tokenLocked(oldToken.getToken(), false);
          return new BaseResponse(StatusCode.UNLOCKED_SUCCESS);
      }
  
      @Override
      public BaseResponse checkUserIsManager(String token) {
          BaseToken baseToken = getRedisUtils().getTokenInfo(token);
          if (null != baseToken) {
              //判断用户的角色是否为空
              if (!StringUtils.isBlank(baseToken.getUserRole())) {
                  //获取系统有操作权限的角色
                  String[] roles = BaseConstants.ADMIN_ROLE_TYPE.split(",");
                  for (String role : roles) {
                      if (-1 != role.indexOf(baseToken.getUserRole())) {
                          return new BaseResponse(StatusCode.AUTHORIZATION_OPERATION);
                      }
                  }
              }
          }
  
          return new BaseResponse(StatusCode.UNAUTHORIZED_OPERATION);
      }
  
  }
  