Преглед на файлове

Merge remote-tracking branch 'origin/assist_sys' into dev2

# Conflicts:
#	PCS/src/main/java/cn/cslg/permission/service/LoginService.java
lwhhszx преди 1 година
родител
ревизия
8fecb3fd82
променени са 17 файла, в които са добавени 889 реда и са изтрити 26 реда
  1. 5 5
      PCS/pom.xml
  2. 26 0
      PCS/src/main/java/cn/cslg/permission/common/model/dto/EncryptionFunctionDTO.java
  3. 39 0
      PCS/src/main/java/cn/cslg/permission/common/model/dto/EncryptionLoginDTO.java
  4. 13 0
      PCS/src/main/java/cn/cslg/permission/common/model/vo/EncryptionFunctionFinalVO.java
  5. 14 0
      PCS/src/main/java/cn/cslg/permission/common/model/vo/EncryptionFunctionVO.java
  6. 22 0
      PCS/src/main/java/cn/cslg/permission/common/model/vo/EncryptionLoginVO.java
  7. 39 0
      PCS/src/main/java/cn/cslg/permission/common/utils/AESUtils.java
  8. 317 0
      PCS/src/main/java/cn/cslg/permission/common/utils/RSAUtils.java
  9. 6 1
      PCS/src/main/java/cn/cslg/permission/common/utils/ResponseEnum.java
  10. 13 0
      PCS/src/main/java/cn/cslg/permission/controller/LoginController.java
  11. 18 0
      PCS/src/main/java/cn/cslg/permission/domain/Personnel.java
  12. 39 0
      PCS/src/main/java/cn/cslg/permission/domain/associate/AssoFunctionModule.java
  13. 40 0
      PCS/src/main/java/cn/cslg/permission/domain/associate/AssoPersonnelMachine.java
  14. 15 0
      PCS/src/main/java/cn/cslg/permission/mapper/associate/AssoFunctionModuleMapper.java
  15. 15 0
      PCS/src/main/java/cn/cslg/permission/mapper/associate/AssoPersonnelMachineMapper.java
  16. 193 20
      PCS/src/main/java/cn/cslg/permission/service/LoginService.java
  17. 75 0
      PCS/src/test/java/cn/cslg/permission/EncryptionPersonTest.java

+ 5 - 5
PCS/pom.xml

@@ -164,11 +164,11 @@
             <artifactId>pagehelper-spring-boot-starter</artifactId>
             <version>1.4.6</version>
         </dependency>
-<!--        <dependency>-->
-<!--            <groupId>org.springframework.boot</groupId>-->
-<!--            <artifactId>spring-boot-starter-test</artifactId>-->
-<!--            <scope>test</scope>-->
-<!--        </dependency>-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>javax.servlet</groupId>
             <artifactId>javax.servlet-api</artifactId>

+ 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;
+
+
+}

+ 13 - 0
PCS/src/main/java/cn/cslg/permission/common/model/vo/EncryptionFunctionFinalVO.java

@@ -0,0 +1,13 @@
+package cn.cslg.permission.common.model.vo;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class EncryptionFunctionFinalVO {
+
+    private String key;
+
+    private List<EncryptionFunctionVO> functionVOS;
+}

+ 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;
+}

+ 39 - 0
PCS/src/main/java/cn/cslg/permission/common/utils/AESUtils.java

@@ -0,0 +1,39 @@
+package cn.cslg.permission.common.utils;
+
+import org.springframework.stereotype.Component;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import java.security.SecureRandom;
+import java.util.Base64;
+
+@Component
+public class AESUtils {
+
+    private static final String ALGORITHM = "AES";
+    private static final int KEY_SIZE = 128;
+
+    public static String generateKey() throws Exception {
+        KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM);
+        keyGenerator.init(KEY_SIZE, new SecureRandom());
+        SecretKey secretKey = keyGenerator.generateKey();
+        return Base64.getEncoder().encodeToString(secretKey.getEncoded());
+    }
+
+    public static String encrypt(String data, String key) throws Exception {
+        Cipher cipher = Cipher.getInstance(ALGORITHM);
+        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(Base64.getDecoder().decode(key), ALGORITHM));
+        byte[] encryptedData = cipher.doFinal(data.getBytes());
+        return Base64.getEncoder().encodeToString(encryptedData);
+    }
+
+    public static String decrypt(String encryptedData, String key) throws Exception {
+        Cipher cipher = Cipher.getInstance(ALGORITHM);
+        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(Base64.getDecoder().decode(key), ALGORITHM));
+        byte[] decryptedData = cipher.doFinal(Base64.getDecoder().decode(encryptedData));
+        return new String(decryptedData);
+    }
+
+}

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

@@ -0,0 +1,317 @@
+package cn.cslg.permission.common.utils;
+
+import org.springframework.stereotype.Component;
+
+import javax.crypto.Cipher;
+import java.io.ByteArrayOutputStream;
+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;
+    //RSA最大加密明文大小
+    private static final int MAX_ENCRYPT_BLOCK = 245;
+    //RSA最大解密密文大小
+    private static final int MAX_DECRYPT_BLOCK = 256;
+
+    /**
+     * 生成密钥对
+     *
+     * @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);
+        //对数据加密
+        int inputLen = data.getBytes().length;
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        int offset = 0;
+        byte[] cache;
+        int i = 0;
+        // 对数据分段加密
+        while (inputLen - offset > 0) {
+            if (inputLen - offset > MAX_ENCRYPT_BLOCK) {
+                cache = cipher.doFinal(data.getBytes(), offset, MAX_ENCRYPT_BLOCK);
+            } else {
+                cache = cipher.doFinal(data.getBytes(), offset, inputLen - offset);
+            }
+            out.write(cache, 0, cache.length);
+            i++;
+            offset = i * MAX_ENCRYPT_BLOCK;
+        }
+        byte[] encryptedData = out.toByteArray();
+        out.close();
+        //返回base64编码后的字符串
+        return Base64.getEncoder().encodeToString(encryptedData);
+    }
+
+    /**
+     * 私钥解密(用于数据解密)    分段解密
+     *
+     * @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[] decodeBytes = Base64.getDecoder().decode(data);
+        //对数据分段解密
+        int inputLen = decodeBytes.length;
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        int offset = 0;
+        byte[] cache;
+        int i = 0;
+        // 对数据分段解密
+        while (inputLen - offset > 0) {
+            if (inputLen - offset > MAX_DECRYPT_BLOCK) {
+                cache = cipher.doFinal(decodeBytes, offset, MAX_DECRYPT_BLOCK);
+            } else {
+                cache = cipher.doFinal(decodeBytes, offset, inputLen - offset);
+            }
+            out.write(cache, 0, cache.length);
+            i++;
+            offset = i * MAX_DECRYPT_BLOCK;
+        }
+        byte[] decryptedData = out.toByteArray();
+        out.close();
+        //返回字符串
+        return new String(decryptedData, "UTF-8");
+    }
+
+    /**
+     * 公钥加密(用于数据加密)
+     *
+     * @param data         加密前的字符串
+     * @param publicKeyStr base64编码后的公钥
+     * @return base64编码后的字符串
+     * @throws Exception
+     */
+    public static String encryptByPublicKey1(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 decryptByPrivateKey1(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, "请求失败"),
     TENANT_STATUS_ERROR(805, "该用户的租户未启用"),
     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;

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

@@ -1,6 +1,8 @@
 package cn.cslg.permission.controller;
 
 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.utils.Response;
 import cn.cslg.permission.common.utils.auth.checkAuth;
@@ -69,4 +71,15 @@ public class LoginController {
         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);
+    }
 }

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

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

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

@@ -0,0 +1,39 @@
+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_FUNCTION_MODULE")
+public class AssoFunctionModule extends BaseEntity<AssoFunctionModule> {
+
+    /**
+     * 关联功能id
+     */
+    @TableField(value = "FUNCTION_ID")
+    private Integer functionId;
+
+    /**
+     * 功能模块代码
+     */
+    @TableField(value = "CODE")
+    private String code;
+
+    /**
+     * 代码授权类型  1未授权2授权
+     */
+    @TableField(value = "AUTH_TYPE")
+    private Integer authType;
+}

+ 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> {
+}

+ 193 - 20
PCS/src/main/java/cn/cslg/permission/service/LoginService.java

@@ -30,9 +30,6 @@ import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
-import org.springframework.web.context.request.RequestAttributes;
-import org.springframework.web.context.request.RequestContextHolder;
-import org.springframework.web.context.request.ServletRequestAttributes;
 
 import javax.servlet.ServletRequest;
 import java.util.*;
@@ -56,7 +53,7 @@ public class LoginService extends ServiceImpl<PersonnelMapper, Personnel> {
     private final PerDpService perDpService;
     private final SystemService systemService;
     private final LoginRecordService loginRecordService;
-//    private final HttpServletRequest request;
+    private final HttpServletRequest request;
 
     /**
      * @param loginVO 登录参数类
@@ -64,10 +61,6 @@ public class LoginService extends ServiceImpl<PersonnelMapper, Personnel> {
      * @author 沈永艺
      */
     public String login(LoginVO loginVO) {
-        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
-        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
-        HttpServletRequest httpRequest = sra.getRequest();
-
         LoginRecordVO loginRecordVO = new LoginRecordVO();
         loginRecordVO.setLoginSystem(loginVO.getLoginSystem());
         //获取已经存放进Redis的验证码 格式: verify-code:uuid(参数)
@@ -90,18 +83,8 @@ public class LoginService extends ServiceImpl<PersonnelMapper, Personnel> {
         //登录日志记录租户id
         loginRecordVO.setTenantId(personnel.getTenantId());
         //登录日志记录ip地址
-        String ipAddress = httpRequest.getHeader("X-Forwarded-For");
-        System.out.println(ipAddress);
-        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
-            ipAddress = httpRequest.getHeader("X-Real-IP");
-            System.out.println("未获得1"+ipAddress);
-        }
-        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
-            ipAddress = httpRequest.getRemoteAddr();
-            System.out.println("未获得2"+ipAddress);
-        }
-        loginRecordVO.setLoginIp(ipAddress);
-        String ua = httpRequest.getHeader("User-Agent");
+        loginRecordVO.setLoginIp(request.getRemoteAddr());
+        String ua = request.getHeader("User-Agent");
         UserAgent userAgent = UserAgent.parseUserAgentString(ua);
         //获取客户端操作系统
         String os = userAgent.getOperatingSystem().getName();
@@ -331,8 +314,198 @@ public class LoginService extends ServiceImpl<PersonnelMapper, Personnel> {
             map.put("value2", personnel.getPersonnelName());
             mailUtils.sendEmailMessage(map);
         }
+    }
 
+    /**
+     * 登录加密
+     * @param vo
+     * @return
+     * @throws Exception
+     */
+    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
+    public String loginByEncryption(EncryptionLoginDTO vo) throws Exception {
+        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;
+        if (second > 30) {
+            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(), personnel.getSymmetryKey(), 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, String symmetryKey, Integer personId) throws Exception {
+        if (StringUtils.isEmpty(privateKey) || StringUtils.isEmpty(publicKey) || Boolean.TRUE.equals(StringUtils.isEmpty(symmetryKey))) {
+            Map<String, String> map = RSAUtils.generateKey();
+            String publicKeyStr = map.get("publicKeyStr");
+            String privateKeyStr = map.get("privateKeyStr");
+            String generateKey = AESUtils.generateKey();
+            Personnel newPersonnel = personnelMapper.selectById(personId);
+            newPersonnel.setPrivateKey(privateKeyStr);
+            newPersonnel.setPublicKey(publicKeyStr);
+            newPersonnel.setSymmetryKey(generateKey);
+            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 {
+        String sign = vo.getSign();
+        String appKey = vo.getAppKey();
+        long currentTimeMillis = vo.getCurrentTimeMillis() / 1000;
+        long currentTimeSecond = System.currentTimeMillis() / 1000;
+        long second = currentTimeSecond - currentTimeMillis;
+        if (second > 30) {
+            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);
+        }
+        String publicKey = personnel.getPublicKey();
+        String symmetryKey = personnel.getSymmetryKey();
+        EncryptionFunctionFinalVO finalVO = new EncryptionFunctionFinalVO();
+        List<EncryptionFunctionVO> functionVOS = new ArrayList<>();
+
+        List<String> permissions = new ArrayList<>();
+        //1.获取该人员角色下权限id
+        List<Integer> functionIds = roleFunctionDataService.getPermission(StpUtil.getLoginIdAsInt());
+        if (!CollectionUtils.isEmpty(functionIds)) {
+            //2.用IDList在功能表中查出对应功能信息
+            List<Function> functionList = functionService.listByIds(functionIds);
+            //3.获取该人员角色所有权限
+            functionList.forEach(i -> {
+                permissions.add(i.getFunctionPath());
+            });
+        }
+        List<EncryptionFunctionVO> list = this.loadFunctionVOS(permissions, 2, symmetryKey);
+        functionVOS.addAll(list);
+
+        List<String> permissions1 = new ArrayList<>();
+        //获取所有权限
+        List<Function> functionList1 = functionService.list();
+
+        functionList1.forEach(i -> {
+            permissions1.add(i.getFunctionPath());
+        });
+        permissions1.removeAll(permissions);
+        List<EncryptionFunctionVO> list1 = this.loadFunctionVOS(permissions1, 1, symmetryKey);
+        functionVOS.addAll(list1);
+        finalVO.setFunctionVOS(functionVOS);
+        String key = RSAUtils.encryptByPublicKey(symmetryKey, publicKey);
+        finalVO.setKey(key);
+        return Response.success(finalVO);
+    }
+
+    private List<EncryptionFunctionVO> loadFunctionVOS(List<String> permissions, Integer type, String symmetryKey) throws Exception {
+        List<EncryptionFunctionVO> functionVOS = new ArrayList<>();
+        List<Function> functions = functionMapper.selectList(new LambdaQueryWrapper<Function>()
+                .in(Function::getFunctionPath, permissions));
+        for (Function function : functions) {
+            Integer functionId = function.getId();
+            String functionPath = function.getFunctionPath();
+            AssoFunctionModule functionModule = assoFunctionModuleMapper.selectOne(new LambdaQueryWrapper<AssoFunctionModule>()
+                    .eq(AssoFunctionModule::getFunctionId, functionId)
+                    .eq(AssoFunctionModule::getAuthType, type));
+            if (ObjectUtils.isNotEmpty(functionModule) && StringUtils.isNotEmpty(functionModule.getCode())) {
+                String moduleCode = functionModule.getCode();
+                String encryptInfo = AESUtils.encrypt(moduleCode, symmetryKey);
+                EncryptionFunctionVO functionVO = new EncryptionFunctionVO();
+                functionVO.setPermission(functionPath);
+                functionVO.setEncryptionModuleCode(encryptInfo);
+                functionVOS.add(functionVO);
+            }
+        }
+        return functionVOS;
+    }
 }

Файловите разлики са ограничени, защото са твърде много
+ 75 - 0
PCS/src/test/java/cn/cslg/permission/EncryptionPersonTest.java