Browse Source

add encryption

zero 1 year ago
parent
commit
d926d359dd

+ 26 - 0
PCS/src/main/java/cn/cslg/permission/common/model/dto/EncryptionFunctionDTO.java

@@ -0,0 +1,26 @@
+package cn.cslg.permission.common.model.dto;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class EncryptionFunctionDTO {
+
+    /**
+     * 请求的secret
+     */
+    private String sign;
+
+    /**
+     * 应用key
+     */
+    private String appKey;
+
+    /**
+     * 发起请求时的时间戳
+     */
+    private Long currentTimeMillis;
+
+    private List<String> permissions;
+}

+ 39 - 0
PCS/src/main/java/cn/cslg/permission/common/model/dto/EncryptionLoginDTO.java

@@ -0,0 +1,39 @@
+package cn.cslg.permission.common.model.dto;
+
+import lombok.Data;
+
+@Data
+public class EncryptionLoginDTO {
+
+    /**
+     * 用户名
+     */
+    private String username;
+
+    /**
+     * 密码
+     */
+    private String password;
+
+    /**
+     * 机器码
+     */
+    private String machineCode;
+
+    /**
+     * 请求的secret
+     */
+    private String sign;
+
+    /**
+     * 应用key
+     */
+    private String appKey;
+
+    /**
+     * 发起请求时的时间戳
+     */
+    private Long currentTimeMillis;
+
+
+}

+ 14 - 0
PCS/src/main/java/cn/cslg/permission/common/model/vo/EncryptionFunctionVO.java

@@ -0,0 +1,14 @@
+package cn.cslg.permission.common.model.vo;
+
+import lombok.Data;
+
+@Data
+public class EncryptionFunctionVO {
+
+    //权限
+    private String permission;
+
+    //加密后的权限对应的模块化代码
+    private String encryptionModuleCode;
+
+}

+ 22 - 0
PCS/src/main/java/cn/cslg/permission/common/model/vo/EncryptionLoginVO.java

@@ -0,0 +1,22 @@
+package cn.cslg.permission.common.model.vo;
+
+import lombok.Data;
+
+@Data
+public class EncryptionLoginVO {
+    private Integer personId;
+    private String personnelName;
+    private String personnelUserName;
+    private String personnelPhone;
+
+    //机器码
+    private String machineCode;
+
+    //私钥
+    private String privateKey;
+
+    /**
+     * 登陆成功后生成的Token
+     */
+    private String token;
+}

+ 223 - 0
PCS/src/main/java/cn/cslg/permission/common/utils/RSAUtils.java

@@ -0,0 +1,223 @@
+package cn.cslg.permission.common.utils;
+
+import org.springframework.stereotype.Component;
+
+import javax.crypto.Cipher;
+import java.security.*;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.Map;
+
+@Component
+public class RSAUtils {
+
+    //签名算法名称
+    private static final String RSA_KEY_ALGORITHM = "RSA";
+
+    //标准签名算法名称
+    private static final String RSA_SIGNATURE_ALGORITHM = "SHA1withRSA";
+    private static final String RSA2_SIGNATURE_ALGORITHM = "SHA256withRSA";
+
+    //RSA密钥长度,默认密钥长度是1024,密钥长度必须是64的倍数,在512到65536位之间,不管是RSA还是RSA2长度推荐使用2048
+    private static final int KEY_SIZE = 2048;
+
+    /**
+     * 生成密钥对
+     *
+     * @return 返回包含公私钥的map
+     */
+    public static Map<String, String> generateKey() {
+        KeyPairGenerator keygen;
+        try {
+            keygen = KeyPairGenerator.getInstance(RSA_KEY_ALGORITHM);
+        } catch (Exception e) {
+            throw new RuntimeException("RSA初始化密钥出现错误,算法异常");
+        }
+        SecureRandom secrand = new SecureRandom();
+        //初始化随机产生器
+        secrand.setSeed("China".getBytes());
+        //初始化密钥生成器
+        keygen.initialize(KEY_SIZE, secrand);
+        KeyPair keyPair = keygen.genKeyPair();
+        //获取公钥并转成base64编码
+        byte[] publicKey = keyPair.getPublic().getEncoded();
+        String publicKeyStr = Base64.getEncoder().encodeToString(publicKey);
+        //获取私钥并转成base64编码
+        byte[] privateKey = keyPair.getPrivate().getEncoded();
+        String privateKeyStr = Base64.getEncoder().encodeToString(privateKey);
+        //创建一个Map返回结果
+        Map<String, String> keyPairMap = new HashMap<>();
+        keyPairMap.put("publicKeyStr", publicKeyStr);
+        keyPairMap.put("privateKeyStr", privateKeyStr);
+        return keyPairMap;
+    }
+
+    /**
+     * 公钥加密(用于数据加密)
+     *
+     * @param data         加密前的字符串
+     * @param publicKeyStr base64编码后的公钥
+     * @return base64编码后的字符串
+     * @throws Exception
+     */
+    public static String encryptByPublicKey(String data, String publicKeyStr) throws Exception {
+        //Java原生base64解码
+        byte[] pubKey = Base64.getDecoder().decode(publicKeyStr);
+        //创建X509编码密钥规范
+        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pubKey);
+        //返回转换指定算法的KeyFactory对象
+        KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
+        //根据X509编码密钥规范产生公钥对象
+        PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
+        //根据转换的名称获取密码对象Cipher(转换的名称:算法/工作模式/填充模式)
+        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
+        //用公钥初始化此Cipher对象(加密模式)
+        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
+        //对数据加密
+        byte[] encrypt = cipher.doFinal(data.getBytes());
+        //返回base64编码后的字符串
+        return Base64.getEncoder().encodeToString(encrypt);
+    }
+
+    /**
+     * 私钥解密(用于数据解密)
+     *
+     * @param data          解密前的字符串
+     * @param privateKeyStr 私钥
+     * @return 解密后的字符串
+     * @throws Exception
+     */
+    public static String decryptByPrivateKey(String data, String privateKeyStr) throws Exception {
+        //Java原生base64解码
+        byte[] priKey = Base64.getDecoder().decode(privateKeyStr);
+        //创建PKCS8编码密钥规范
+        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(priKey);
+        //返回转换指定算法的KeyFactory对象
+        KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
+        //根据PKCS8编码密钥规范产生私钥对象
+        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
+        //根据转换的名称获取密码对象Cipher(转换的名称:算法/工作模式/填充模式)
+        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
+        //用私钥初始化此Cipher对象(解密模式)
+        cipher.init(Cipher.DECRYPT_MODE, privateKey);
+        //对数据解密
+        byte[] decrypt = cipher.doFinal(Base64.getDecoder().decode(data));
+        //返回字符串
+        return new String(decrypt);
+    }
+
+    /**
+     * 私钥加密(用于数据签名)
+     *
+     * @param data          加密前的字符串
+     * @param privateKeyStr base64编码后的私钥
+     * @return base64编码后后的字符串
+     * @throws Exception
+     */
+    public static String encryptByPrivateKey(String data, String privateKeyStr) throws Exception {
+        //Java原生base64解码
+        byte[] priKey = Base64.getDecoder().decode(privateKeyStr);
+        //创建PKCS8编码密钥规范
+        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(priKey);
+        //返回转换指定算法的KeyFactory对象
+        KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
+        //根据PKCS8编码密钥规范产生私钥对象
+        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
+        //根据转换的名称获取密码对象Cipher(转换的名称:算法/工作模式/填充模式)
+        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
+        //用私钥初始化此Cipher对象(加密模式)
+        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
+        //对数据加密
+        byte[] encrypt = cipher.doFinal(data.getBytes());
+        //返回base64编码后的字符串
+        return Base64.getEncoder().encodeToString(encrypt);
+    }
+
+    /**
+     * 公钥解密(用于数据验签)
+     *
+     * @param data         解密前的字符串
+     * @param publicKeyStr base64编码后的公钥
+     * @return 解密后的字符串
+     * @throws Exception
+     */
+    public static String decryptByPublicKey(String data, String publicKeyStr) throws Exception {
+        //Java原生base64解码
+        byte[] pubKey = Base64.getDecoder().decode(publicKeyStr);
+        //创建X509编码密钥规范
+        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pubKey);
+        //返回转换指定算法的KeyFactory对象
+        KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
+        //根据X509编码密钥规范产生公钥对象
+        PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
+        //根据转换的名称获取密码对象Cipher(转换的名称:算法/工作模式/填充模式)
+        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
+        //用公钥初始化此Cipher对象(解密模式)
+        cipher.init(Cipher.DECRYPT_MODE, publicKey);
+        //对数据解密
+        byte[] decrypt = cipher.doFinal(Base64.getDecoder().decode(data));
+        //返回字符串
+        return new String(decrypt);
+    }
+
+    /**
+     * RSA签名
+     *
+     * @param data     待签名数据
+     * @param priKey   私钥
+     * @param signType RSA或RSA2
+     * @return 签名
+     * @throws Exception
+     */
+    public static String sign(byte[] data, byte[] priKey, String signType) throws Exception {
+        //创建PKCS8编码密钥规范
+        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(priKey);
+        //返回转换指定算法的KeyFactory对象
+        KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
+        //根据PKCS8编码密钥规范产生私钥对象
+        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
+        //标准签名算法名称(RSA还是RSA2)
+        String algorithm = RSA_KEY_ALGORITHM.equals(signType) ? RSA_SIGNATURE_ALGORITHM : RSA2_SIGNATURE_ALGORITHM;
+        //用指定算法产生签名对象Signature
+        Signature signature = Signature.getInstance(algorithm);
+        //用私钥初始化签名对象Signature
+        signature.initSign(privateKey);
+        //将待签名的数据传送给签名对象(须在初始化之后)
+        signature.update(data);
+        //返回签名结果字节数组
+        byte[] sign = signature.sign();
+        //返回Base64编码后的字符串
+        return Base64.getEncoder().encodeToString(sign);
+    }
+
+    /**
+     * RSA校验数字签名
+     *
+     * @param data     待校验数据
+     * @param sign     数字签名
+     * @param pubKey   公钥
+     * @param signType RSA或RSA2
+     * @return boolean 校验成功返回true,失败返回false
+     */
+    public static boolean verify(byte[] data, byte[] sign, byte[] pubKey, String signType) throws Exception {
+        //返回转换指定算法的KeyFactory对象
+        KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
+        //创建X509编码密钥规范
+        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pubKey);
+        //根据X509编码密钥规范产生公钥对象
+        PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
+        //标准签名算法名称(RSA还是RSA2)
+        String algorithm = RSA_KEY_ALGORITHM.equals(signType) ? RSA_SIGNATURE_ALGORITHM : RSA2_SIGNATURE_ALGORITHM;
+        //用指定算法产生签名对象Signature
+        Signature signature = Signature.getInstance(algorithm);
+        //用公钥初始化签名对象,用于验证签名
+        signature.initVerify(publicKey);
+        //更新签名内容
+        signature.update(data);
+        //得到验证结果
+        return signature.verify(sign);
+    }
+
+}

+ 6 - 1
PCS/src/main/java/cn/cslg/permission/common/utils/ResponseEnum.java

@@ -24,7 +24,12 @@ public enum ResponseEnum {
     ERROR(0, "请求失败"),
     ERROR(0, "请求失败"),
     TENANT_STATUS_ERROR(805, "该用户的租户未启用"),
     TENANT_STATUS_ERROR(805, "该用户的租户未启用"),
     PERSONNEL_STATUS_ERROR(806, "该用户未启用"),
     PERSONNEL_STATUS_ERROR(806, "该用户未启用"),
-    TENANT_DEADLINE_ERROR(0, "该用户的租户已过期");
+    TENANT_DEADLINE_ERROR(0, "该用户的租户已过期"),
+    THE_TOKEN_IS_INVALID(500, "token失效"),
+    THE_REQUEST_TIME_OVERTIME(500, "请求时间超时"),
+    THE_SIGN_IS_NOT_SAME(500, "请求SIGN不一致,重新检查"),
+    THE_MACHINE_CODE_IS_NULL(500, "机器码不可为空"),
+    DO_NOT_LOG_IN_TO_MORE_THAN_TWO_NEW_MACHINES_WITH_THE_SAME_ACCOUNT(500, "同一账号新机登录不可超过两个");
 
 
 
 
     private Integer code;
     private Integer code;

+ 13 - 0
PCS/src/main/java/cn/cslg/permission/controller/LoginController.java

@@ -1,6 +1,8 @@
 package cn.cslg.permission.controller;
 package cn.cslg.permission.controller;
 
 
 import cn.cslg.permission.common.core.base.Constants;
 import cn.cslg.permission.common.core.base.Constants;
+import cn.cslg.permission.common.model.dto.EncryptionFunctionDTO;
+import cn.cslg.permission.common.model.dto.EncryptionLoginDTO;
 import cn.cslg.permission.common.model.vo.LoginVO;
 import cn.cslg.permission.common.model.vo.LoginVO;
 import cn.cslg.permission.common.utils.Response;
 import cn.cslg.permission.common.utils.Response;
 import cn.cslg.permission.common.utils.auth.checkAuth;
 import cn.cslg.permission.common.utils.auth.checkAuth;
@@ -69,4 +71,15 @@ public class LoginController {
         return Response.success();
         return Response.success();
     }
     }
 
 
+    @Operation(summary = "登录加密")
+    @PostMapping("/loginByEncryption")
+    public String loginByEncryption(@RequestBody EncryptionLoginDTO vo) throws Exception {
+        return loginService.loginByEncryption(vo);
+    }
+
+    @Operation(summary = "功能模块化代码加密")
+    @PostMapping("/functionByEncryption")
+    public String functionByEncryption(@RequestBody EncryptionFunctionDTO vo) throws Exception {
+        return loginService.functionByEncryption(vo);
+    }
 }
 }

+ 12 - 0
PCS/src/main/java/cn/cslg/permission/domain/Personnel.java

@@ -92,4 +92,16 @@ public class Personnel extends BaseEntity<Personnel> {
      */
      */
     @TableField(value = "TENANT_ID")
     @TableField(value = "TENANT_ID")
     private Integer tenantId;
     private Integer tenantId;
+
+    /**
+     * 私钥
+     */
+    @TableField(value = "PRIVATE_KEY")
+    private String privateKey;
+
+    /**
+     * 公钥
+     */
+    @TableField(value = "PUBLIC_KEY")
+    private String publicKey;
 }
 }

+ 34 - 0
PCS/src/main/java/cn/cslg/permission/domain/associate/AssoFunctionModule.java

@@ -0,0 +1,34 @@
+package cn.cslg.permission.domain.associate;
+
+import cn.cslg.permission.common.model.BaseEntity;
+import cn.cslg.permission.domain.Personnel;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * @author 沈永艺
+ * @date 2022-8-2
+ * @description 功能模块代码关联表
+ */
+
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = true)
+@TableName(value = "ASSO_FUNCTION_MODULE")
+public class AssoFunctionModule extends BaseEntity<AssoFunctionModule> {
+
+    /**
+     * 关联功能id
+     */
+    @TableField(value = "FUNCTION_ID")
+    private Integer functionId;
+
+    /**
+     * 功能模块代码
+     */
+    @TableField(value = "CODE")
+    private String code;
+}

+ 40 - 0
PCS/src/main/java/cn/cslg/permission/domain/associate/AssoPersonnelMachine.java

@@ -0,0 +1,40 @@
+package cn.cslg.permission.domain.associate;
+
+import cn.cslg.permission.common.model.BaseEntity;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * @author 沈永艺
+ * @date 2022-8-2
+ * @description 人员机器码关联表
+ */
+
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = true)
+@TableName(value = "ASSO_PERSONNEL_MACHINE")
+public class AssoPersonnelMachine extends BaseEntity<AssoPersonnelMachine> {
+
+    /**
+     * 人员id
+     */
+    @TableField(value = "PERSONNEL_ID")
+    private Integer personnelId;
+
+    /**
+     * 机器码
+     */
+    @TableField(value = "MACHINE_CODE")
+    private String machineCode;
+
+
+    /**
+     * 是否首次激活(1是0否)
+     */
+    @TableField(value = "IF_FIRST_ACTIVATION")
+    private Boolean ifFirstActivation;
+}

+ 15 - 0
PCS/src/main/java/cn/cslg/permission/mapper/associate/AssoFunctionModuleMapper.java

@@ -0,0 +1,15 @@
+package cn.cslg.permission.mapper.associate;
+
+import cn.cslg.permission.domain.associate.AssoFunctionModule;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author 沈永艺
+ * @date 2022-8-2
+ * @description 关联类 功能模块代码 Mapper 层
+ */
+
+@Repository
+public interface AssoFunctionModuleMapper extends BaseMapper<AssoFunctionModule> {
+}

+ 15 - 0
PCS/src/main/java/cn/cslg/permission/mapper/associate/AssoPersonnelMachineMapper.java

@@ -0,0 +1,15 @@
+package cn.cslg.permission.mapper.associate;
+
+import cn.cslg.permission.domain.associate.AssoPersonnelMachine;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author 沈永艺
+ * @date 2022-8-2
+ * @description 关联类 人员机器码 Mapper 层
+ */
+
+@Repository
+public interface AssoPersonnelMachineMapper extends BaseMapper<AssoPersonnelMachine> {
+}

+ 174 - 6
PCS/src/main/java/cn/cslg/permission/service/LoginService.java

@@ -1,16 +1,21 @@
 package cn.cslg.permission.service;
 package cn.cslg.permission.service;
 
 
 import cn.cslg.permission.common.core.base.RedisConf;
 import cn.cslg.permission.common.core.base.RedisConf;
-import cn.cslg.permission.common.model.vo.LoginRecordVO;
-import cn.cslg.permission.common.model.vo.LoginVO;
-import cn.cslg.permission.common.model.vo.PersonnelVO;
-import cn.cslg.permission.common.model.vo.RoleVO;
+import cn.cslg.permission.common.model.dto.EncryptionFunctionDTO;
+import cn.cslg.permission.common.model.dto.EncryptionLoginDTO;
+import cn.cslg.permission.common.model.vo.*;
 import cn.cslg.permission.common.utils.*;
 import cn.cslg.permission.common.utils.*;
 import cn.cslg.permission.common.utils.message.MessageUtils;
 import cn.cslg.permission.common.utils.message.MessageUtils;
+import cn.cslg.permission.domain.Function;
 import cn.cslg.permission.domain.Personnel;
 import cn.cslg.permission.domain.Personnel;
 import cn.cslg.permission.domain.ReSetPasswordDTO;
 import cn.cslg.permission.domain.ReSetPasswordDTO;
 import cn.cslg.permission.domain.Tenant;
 import cn.cslg.permission.domain.Tenant;
+import cn.cslg.permission.domain.associate.AssoFunctionModule;
+import cn.cslg.permission.domain.associate.AssoPersonnelMachine;
+import cn.cslg.permission.mapper.FunctionMapper;
 import cn.cslg.permission.mapper.PersonnelMapper;
 import cn.cslg.permission.mapper.PersonnelMapper;
+import cn.cslg.permission.mapper.associate.AssoFunctionModuleMapper;
+import cn.cslg.permission.mapper.associate.AssoPersonnelMachineMapper;
 import cn.cslg.permission.service.associate.PerDpService;
 import cn.cslg.permission.service.associate.PerDpService;
 import cn.cslg.permission.service.associate.PersonRoleService;
 import cn.cslg.permission.service.associate.PersonRoleService;
 import cn.dev33.satoken.stp.StpUtil;
 import cn.dev33.satoken.stp.StpUtil;
@@ -28,10 +33,12 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import lombok.RequiredArgsConstructor;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ObjectUtils;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
-
-import javax.servlet.ServletRequest;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
 import java.util.*;
 import java.util.*;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeUnit;
 
 
@@ -54,6 +61,14 @@ public class LoginService extends ServiceImpl<PersonnelMapper, Personnel> {
     private final SystemService systemService;
     private final SystemService systemService;
     private final LoginRecordService loginRecordService;
     private final LoginRecordService loginRecordService;
     private final HttpServletRequest request;
     private final HttpServletRequest request;
+    @Autowired
+    private PersonnelMapper personnelMapper;
+    @Autowired
+    private FunctionMapper functionMapper;
+    @Autowired
+    private AssoPersonnelMachineMapper assoPersonnelMachineMapper;
+    @Autowired
+    private AssoFunctionModuleMapper assoFunctionModuleMapper;
 
 
     /**
     /**
      * @param loginVO 登录参数类
      * @param loginVO 登录参数类
@@ -314,8 +329,161 @@ public class LoginService extends ServiceImpl<PersonnelMapper, Personnel> {
             map.put("value2", personnel.getPersonnelName());
             map.put("value2", personnel.getPersonnelName());
             mailUtils.sendEmailMessage(map);
             mailUtils.sendEmailMessage(map);
         }
         }
+    }
 
 
+    /**
+     * 登录加密
+     * @param vo
+     * @return
+     * @throws Exception
+     */
+    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
+    public String loginByEncryption(EncryptionLoginDTO vo) {
+        final String username = vo.getUsername();
+        final String password = vo.getPassword();
+        String machineCode = vo.getMachineCode();
+        final String sign = vo.getSign();
+        final String appKey = vo.getAppKey();
+        long currentTimeMillis = vo.getCurrentTimeMillis() / 1000;
+        long currentTimeSecond = System.currentTimeMillis() / 1000;
+        final long second = currentTimeSecond - currentTimeMillis / 1000;
+        if (second > 5) {
+            return Response.error(ResponseEnum.THE_REQUEST_TIME_OVERTIME);
+        }
+        String appSecret = appKey + currentTimeMillis;
+        String md5Sign = SecureUtil.md5(appSecret);
+        if (Boolean.TRUE.equals(StringUtils.isEmpty(sign)) || !sign.equals(md5Sign)) {
+            return Response.error(ResponseEnum.THE_SIGN_IS_NOT_SAME);
+        }
+        if (Boolean.TRUE.equals(StringUtils.isEmpty(machineCode))) {
+            return Response.error(ResponseEnum.THE_MACHINE_CODE_IS_NULL);
+        }
+        //用用户名查询人员信息
+        LambdaQueryWrapper<Personnel> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(Personnel::getPersonnelUserName, username);
+        //获取一条
+        Personnel personnel = this.getOne(queryWrapper);
+        final Integer personId = personnel.getId();
+        //如果查不到 报错 用户名不存在
+        if (ObjectUtils.isEmpty(personnel)) {
+            return Response.error(ResponseEnum.USERNAME_ERROR);
+        }
+        //校验密码是否正确
+        boolean isPassword = personnel.getPersonnelPassword().equals(SecureUtil.md5(password));
+        if (!isPassword) {
+            //登录日志记录登录是否成功
+            return Response.error(ResponseEnum.PASSWORD_ERROR);
+        }
+        //人员信息中私钥或公钥为空则添加进去
+        updatePersonnel(personnel.getPrivateKey(), personnel.getPublicKey(), personId);
 
 
+        personnel = personnelMapper.selectById(personnel.getId());
+        List<AssoPersonnelMachine> machineList = assoPersonnelMachineMapper.selectList(new LambdaQueryWrapper<AssoPersonnelMachine>()
+                .eq(AssoPersonnelMachine::getPersonnelId, personId)
+                .ne(AssoPersonnelMachine::getMachineCode, SecureUtil.md5(machineCode)));
+        if (machineList.size() > 1) {
+            return Response.error(ResponseEnum.DO_NOT_LOG_IN_TO_MORE_THAN_TWO_NEW_MACHINES_WITH_THE_SAME_ACCOUNT);
+        }
+        boolean flag = addOrUpdatePersonnelMachine(machineCode, personnel);
+        EncryptionLoginVO loginVO = new EncryptionLoginVO();
+        if (flag) {
+            loginVO.setPrivateKey(personnel.getPrivateKey());
+        }
+        loginVO.setPersonId(personId);
+        loginVO.setPersonnelName(personnel.getPersonnelName());
+        loginVO.setPersonnelUserName(personnel.getPersonnelUserName());
+        loginVO.setPersonnelPhone(personnel.getPersonnelPhone());
+        loginVO.setMachineCode(vo.getMachineCode());
+        //Sa-token 登录方法 登录后 生成Token 如果集成了Redis的话 会自动存入Redis
+        StpUtil.login(personnel.getId());
+        loginVO.setToken(StpUtil.getTokenValue());
+        return Response.success(loginVO);
+    }
+
+    public void updatePersonnel(String privateKey, String publicKey, Integer personId) {
+        if (StringUtils.isEmpty(privateKey) || StringUtils.isEmpty(publicKey)) {
+            Map<String, String> map = RSAUtils.generateKey();
+            String publicKeyStr = map.get("publicKeyStr");
+            String privateKeyStr = map.get("privateKeyStr");
+            Personnel newPersonnel = personnelMapper.selectById(personId);
+            newPersonnel.setPrivateKey(privateKeyStr);
+            newPersonnel.setPublicKey(publicKeyStr);
+            newPersonnel.updateById();
+        }
+    }
+
+    /**
+     * 新增或修改人员机器码关联表
+     *
+     * @param machineCode
+     * @param personnel
+     * @return
+     */
+    private boolean addOrUpdatePersonnelMachine(String machineCode, Personnel personnel) {
+        AssoPersonnelMachine machine = assoPersonnelMachineMapper.selectOne(new LambdaQueryWrapper<AssoPersonnelMachine>()
+                .eq(AssoPersonnelMachine::getMachineCode, SecureUtil.md5(machineCode))
+                .eq(AssoPersonnelMachine::getPersonnelId, personnel.getId()));
+        if (ObjectUtils.isEmpty(machine)) {
+            AssoPersonnelMachine assoPersonnelMachine = new AssoPersonnelMachine();
+            assoPersonnelMachine.setPersonnelId(personnel.getId());
+            assoPersonnelMachine.setMachineCode(SecureUtil.md5(machineCode));
+            assoPersonnelMachine.setIfFirstActivation(true);
+            assoPersonnelMachine.setCreateUser(personnel.getCreateUser());
+            assoPersonnelMachine.setCreateTime(new Date());
+            assoPersonnelMachine.insert();
+            return true;
+        } else {
+            machine.setId(machine.getId());
+            machine.setIfFirstActivation(false);
+            machine.updateById();
+            return false;
+        }
     }
     }
 
 
+    /**
+     * 功能模块化代码加密
+     * @param vo
+     * @return
+     * @throws Exception
+     */
+    public String functionByEncryption(EncryptionFunctionDTO vo) throws Exception {
+        final String sign = vo.getSign();
+        final String appKey = vo.getAppKey();
+        long currentTimeMillis = vo.getCurrentTimeMillis() / 1000;
+        long currentTimeSecond = System.currentTimeMillis() / 1000;
+        final long second = currentTimeSecond - currentTimeMillis;
+        if (second > 5) {
+            return Response.error(ResponseEnum.THE_REQUEST_TIME_OVERTIME);
+        }
+        String appSecret = appKey + currentTimeMillis;
+        String md5Sign = SecureUtil.md5(appSecret);
+        if (Boolean.TRUE.equals(StringUtils.isEmpty(sign)) || !sign.equals(md5Sign)) {
+            return Response.error(ResponseEnum.THE_SIGN_IS_NOT_SAME);
+        }
+        Integer userId = StpUtil.getLoginIdAsInt();
+        Personnel personnel = this.getById(userId);
+        if (ObjectUtils.isEmpty(personnel)) {
+            return Response.error(ResponseEnum.THE_TOKEN_IS_INVALID);
+        }
+        final String publicKey = personnel.getPublicKey();
+        final List<String> permissions = vo.getPermissions();
+        List<EncryptionFunctionVO> functionVOS = new ArrayList<>();
+        List<Function> functions = functionMapper.selectList(new LambdaQueryWrapper<Function>()
+                .in(Function::getFunctionPath, permissions));
+        for (Function function : functions) {
+            final Integer functionId = function.getId();
+            final String functionPath = function.getFunctionPath();
+            final AssoFunctionModule functionModule = assoFunctionModuleMapper.selectOne(new LambdaQueryWrapper<AssoFunctionModule>()
+                    .eq(AssoFunctionModule::getFunctionId, functionId));
+            final String moduleCode = functionModule.getCode();
+            if (StringUtils.isNotEmpty(moduleCode)) {
+                final String encryptInfo = RSAUtils.encryptByPublicKey(moduleCode, publicKey);
+                EncryptionFunctionVO functionVO = new EncryptionFunctionVO();
+                functionVO.setPermission(functionPath);
+                functionVO.setEncryptionModuleCode(encryptInfo);
+                functionVOS.add(functionVO);
+            }
+        }
+        return Response.success(functionVOS);
+    }
 }
 }