update 优化 重构 !pr274 简化结构 解决代码逻辑问题 规范注释

This commit is contained in:
疯狂的狮子li 2023-01-18 14:11:48 +08:00
parent e20dacbfd9
commit d2675744f4
24 changed files with 339 additions and 409 deletions

View File

@ -179,19 +179,20 @@ mybatis-plus:
updateStrategy: NOT_NULL updateStrategy: NOT_NULL
# 字段验证策略之 select,在 select 的时候的字段验证策略既 wrapper 根据内部 entity 生成的 where 条件 # 字段验证策略之 select,在 select 的时候的字段验证策略既 wrapper 根据内部 entity 生成的 where 条件
where-strategy: NOT_NULL where-strategy: NOT_NULL
# 数据加密 # 数据加密
mybatis-encryptor: mybatis-encryptor:
# 是否开启加密 # 是否开启加密
enabled: false enable: false
# 默认加密算法 # 默认加密算法
algorithm: base64 algorithm: BASE64
# 安全秘钥。对称算法的秘钥。如AESSM4 # 编码方式 BASE64/HEX。默认BASE64
# password: QBcc3SHK2G4ijyfl5XQ7@2g!N2j2jRDR encode: BASE64
# # 公私钥。非对称算法的公私钥SM2RSA # 安全秘钥 对称算法的秘钥 如AESSM4
# publicKey: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCDt41GIcWvY6/tpjOLoWY78Oy00uWcNbMRG/8DRoS79/h2D+pV8uxV+0ezaN+fBFCZnK8TdJcPeU4EnNRUh/8HEY33KFvZ700n+Gj5BHUUDKzx3UVFNuF49UI/yoJ8rz6VQQHO79KK89VwmSMO77Tfee1ofe0STY6IwMt/MwaoKwIDAQAB password:
# privateKey: MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIO3jUYhxa9jr+2mM4uhZjvw7LTS5Zw1sxEb/wNGhLv3+HYP6lXy7FX7R7No358EUJmcrxN0lw95TgSc1FSH/wcRjfcoW9nvTSf4aPkEdRQMrPHdRUU24Xj1Qj/KgnyvPpVBAc7v0orz1XCZIw7vtN957Wh97RJNjojAy38zBqgrAgMBAAECgYAkXx4qvI6rFNryw88+Am6JpMioUghHb2ioE9QCYomqohnA+DocS71JLN8qwo3lijp7gJGzzKEeC8Aoc+oKAZfBQQwPP0K/ql+NcLdlqNAr+XyzkZrLJD/BfluQ6mXI23tjonWnPPZ1Et9HC3zXRQPiuh7Ff6UoqatTMI3OIbSyuQJBAPbaJpVYmIsWJdpvaAC6hcGgR/vbG9yX8VphPn8/2wsm2MmQrRkUoKkudE/veX3KQjGikDwo9+bT6aBl+nn2DUUCQQCImSGZFNcGqhMLyRGVogP6fh0YZSEQAhFbZ69nQmplqbie+dREhODH5Vs5F0C2aL5iSR/UaIDkNEA1auX7x56vAkAFWjON927PTTqi4tmBconl6eDFsDmJbe34xLUDM1I/iqcWr8FhEtZs9Knm9c1PkewfgWPZOhYt9hhRtwRYUqJ1AkAPvQ0I9US9KNVe80DKa8tnjiZODEDd9k8HqA+mpxlZM0/pSUGyz1iSz5NOJaa4HaNp8aDwOUY4hOis/u8Wrm5TAkEA00YeUsaXlMyMF/5pjols44tXb54AjAC2mH66pz9JsKg7pKpWVOpEV5rMY58CGZHWau69vGLZnCd1coeMw77YAQ== # 公私钥 非对称算法的公私钥 如SM2RSA
# # 编码方式base64/hex。默认base64 publicKey:
# encode: base64 privateKey:
# Swagger配置 # Swagger配置
swagger: swagger:

View File

@ -1,37 +0,0 @@
package com.ruoyi.test;
import cn.dev33.satoken.annotation.SaIgnore;
import com.ruoyi.demo.domain.TestDemo;
import com.ruoyi.demo.mapper.TestDemoMapper;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
/**
* 加密单元测试案例
*
* @author 老马
* @date 2023-01-12 08:53
*/
@SpringBootTest
@SaIgnore
@DisplayName("加密测试")
public class EncryptUnitTest {
@Resource
private TestDemoMapper demoMapper;
@Test
public void testCrypt() {
TestDemo demo = new TestDemo();
demo.setTestKey("测试的key");
demo.setValue("测试的value");
this.demoMapper.insert(demo);
System.out.println(demo);
TestDemo testDemo = this.demoMapper.selectById(demo.getId());
System.out.println(testDemo);
}
}

View File

@ -19,7 +19,7 @@ public @interface EncryptField {
/** /**
* 加密算法 * 加密算法
*/ */
AlgorithmType algorithm() default AlgorithmType.BASE64; AlgorithmType algorithm() default AlgorithmType.DEFAULT;
/** /**
* 秘钥AESSM4需要 * 秘钥AESSM4需要
@ -39,6 +39,6 @@ public @interface EncryptField {
/** /**
* 编码方式对加密算法为BASE64的不起作用 * 编码方式对加密算法为BASE64的不起作用
*/ */
EncodeType encode() default EncodeType.BASE64; EncodeType encode() default EncodeType.DEFAULT;
} }

View File

@ -1,18 +1,23 @@
package com.ruoyi.common.encrypt; package com.ruoyi.common.encrypt;
import com.ruoyi.common.enums.AlgorithmType;
import com.ruoyi.common.enums.EncodeType; import com.ruoyi.common.enums.EncodeType;
import lombok.Builder;
import lombok.Data; import lombok.Data;
/** /**
* 加密上下文用于encryptor传递必要的参数 * 加密上下文 用于encryptor传递必要的参数
* 隔离配置和注解
* *
* @author 老马 * @author 老马
* @date 2023-01-17 08:31 * @version 4.6.0
*/ */
@Data @Data
public class EncryptContext { public class EncryptContext {
/**
* 默认算法
*/
private AlgorithmType algorithm;
/** /**
* 安全秘钥 * 安全秘钥
*/ */
@ -32,4 +37,5 @@ public class EncryptContext {
* 编码方式base64/hex * 编码方式base64/hex
*/ */
private EncodeType encode; private EncodeType encode;
} }

View File

@ -7,16 +7,12 @@ import com.ruoyi.common.enums.EncodeType;
* 加解者 * 加解者
* *
* @author 老马 * @author 老马
* @date 2023-01-10 16:08 * @version 4.6.0
*/ */
public interface IEncryptor { public interface IEncryptor {
/** /**
* 获得当前算法 * 获得当前算法
*
* @return com.ruoyi.common.enums.AlgorithmType
* @author 老马
* @date 2023/1/11 11:18
*/ */
AlgorithmType algorithm(); AlgorithmType algorithm();
@ -25,22 +21,15 @@ public interface IEncryptor {
* *
* @param value 待加密字符串 * @param value 待加密字符串
* @param encodeType 加密后的编码格式 * @param encodeType 加密后的编码格式
* @return java.lang.String 加密后的字符串 * @return 加密后的字符串
* @throws Exception 抛出异常
* @author 老马
* @date 2023/1/10 16:38
*/ */
String encrypt(String value, EncodeType encodeType) throws Exception; String encrypt(String value, EncodeType encodeType);
/** /**
* 解密 * 解密
* *
* @param value 待加密字符串 * @param value 待加密字符串
* @param encodeType 加密后的编码格式 * @return 解密后的字符串
* @return java.lang.String 解密后的字符串
* @throws Exception 抛出异常
* @author 老马
* @date 2023/1/10 16:38
*/ */
String decrypt(String value, EncodeType encodeType) throws Exception; String decrypt(String value);
} }

View File

@ -7,10 +7,12 @@ import com.ruoyi.common.encrypt.IEncryptor;
* 所有加密执行者的基类 * 所有加密执行者的基类
* *
* @author 老马 * @author 老马
* @date 2023-01-17 16:52 * @version 4.6.0
*/ */
public abstract class AbstractEncryptor implements IEncryptor { public abstract class AbstractEncryptor implements IEncryptor {
public AbstractEncryptor(EncryptContext context) { public AbstractEncryptor(EncryptContext context) {
//子类必须实现带参数的构造方法 // 用户配置校验与配置注入
} }
} }

View File

@ -1,7 +1,6 @@
package com.ruoyi.common.encrypt.encryptor; package com.ruoyi.common.encrypt.encryptor;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil; import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES; import cn.hutool.crypto.symmetric.AES;
@ -15,32 +14,28 @@ import java.nio.charset.StandardCharsets;
* AES算法实现 * AES算法实现
* *
* @author 老马 * @author 老马
* @date 2023-01-06 11:39 * @version 4.6.0
*/ */
public class AesEncryptor extends AbstractEncryptor { public class AesEncryptor extends AbstractEncryptor {
private AES aes = null; private final AES aes;
public AesEncryptor(EncryptContext context) { public AesEncryptor(EncryptContext context) {
super(context); super(context);
String password = context.getPassword(); String password = context.getPassword();
if (StrUtil.isBlank(password)) { if (StrUtil.isBlank(password)) {
throw new RuntimeException("aes没有获得秘钥信息"); throw new IllegalArgumentException("AES没有获得秘钥信息");
} }
// aes算法的秘钥要求是16位24位32位 // aes算法的秘钥要求是16位24位32位
int[] array = {16, 24, 32}; int[] array = {16, 24, 32};
if(!ArrayUtil.contains(array, password.length())) { if (!ArrayUtil.contains(array, password.length())) {
throw new RuntimeException("aes秘钥长度应该为16位、24位、32位实际为"+password.length()+""); throw new IllegalArgumentException("AES秘钥长度应该为16位、24位、32位实际为" + password.length() + "");
} }
aes = SecureUtil.aes(context.getPassword().getBytes(StandardCharsets.UTF_8)); aes = SecureUtil.aes(context.getPassword().getBytes(StandardCharsets.UTF_8));
} }
/** /**
* 获得当前算法 * 获得当前算法
*
* @return com.ruoyi.common.enums.AlgorithmType
* @author 老马
* @date 2023/1/11 11:18
*/ */
@Override @Override
public AlgorithmType algorithm() { public AlgorithmType algorithm() {
@ -52,36 +47,23 @@ public class AesEncryptor extends AbstractEncryptor {
* *
* @param value 待加密字符串 * @param value 待加密字符串
* @param encodeType 加密后的编码格式 * @param encodeType 加密后的编码格式
* @return java.lang.String
* @author 老马
* @date 2023/1/10 16:38
*/ */
@Override @Override
public String encrypt(String value, EncodeType encodeType) throws Exception { public String encrypt(String value, EncodeType encodeType) {
if (ObjectUtil.isNotNull(this.aes)) { if (encodeType == EncodeType.HEX) {
if (encodeType == EncodeType.HEX) { return aes.encryptHex(value);
return aes.encryptHex(value); } else {
} else { return aes.encryptBase64(value);
return aes.encryptBase64(value);
}
} }
return value;
} }
/** /**
* 解密 * 解密
* *
* @param value 待加密字符串 * @param value 待加密字符串
* @param encodeType 加密后的编码格式
* @return java.lang.String
* @author 老马
* @date 2023/1/10 16:38
*/ */
@Override @Override
public String decrypt(String value, EncodeType encodeType) throws Exception { public String decrypt(String value) {
if (ObjectUtil.isNotNull(this.aes)) { return this.aes.decryptStr(value);
return this.aes.decryptStr(value);
}
return value;
} }
} }

View File

@ -6,10 +6,10 @@ import com.ruoyi.common.enums.AlgorithmType;
import com.ruoyi.common.enums.EncodeType; import com.ruoyi.common.enums.EncodeType;
/** /**
* Base64算法实现不建议在生产环境使用 * Base64算法实现
* *
* @author 老马 * @author 老马
* @date 2023-01-06 10:00 * @version 4.6.0
*/ */
public class Base64Encryptor extends AbstractEncryptor { public class Base64Encryptor extends AbstractEncryptor {
@ -19,10 +19,6 @@ public class Base64Encryptor extends AbstractEncryptor {
/** /**
* 获得当前算法 * 获得当前算法
*
* @return com.ruoyi.common.enums.AlgorithmType
* @author 老马
* @date 2023/1/11 11:18
*/ */
@Override @Override
public AlgorithmType algorithm() { public AlgorithmType algorithm() {
@ -34,12 +30,9 @@ public class Base64Encryptor extends AbstractEncryptor {
* *
* @param value 待加密字符串 * @param value 待加密字符串
* @param encodeType 加密后的编码格式 * @param encodeType 加密后的编码格式
* @return java.lang.String
* @author 老马
* @date 2023/1/10 16:38
*/ */
@Override @Override
public String encrypt(String value, EncodeType encodeType) throws Exception { public String encrypt(String value, EncodeType encodeType) {
return Base64.encode(value); return Base64.encode(value);
} }
@ -47,13 +40,9 @@ public class Base64Encryptor extends AbstractEncryptor {
* 解密 * 解密
* *
* @param value 待加密字符串 * @param value 待加密字符串
* @param encodeType 加密后的编码格式
* @return java.lang.String
* @author 老马
* @date 2023/1/10 16:38
*/ */
@Override @Override
public String decrypt(String value, EncodeType encodeType) throws Exception { public String decrypt(String value) {
return Base64.decodeStr(value); return Base64.decodeStr(value);
} }
} }

View File

@ -1,7 +1,6 @@
package com.ruoyi.common.encrypt.encryptor; package com.ruoyi.common.encrypt.encryptor;
import cn.hutool.core.codec.Base64; import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.SecureUtil; import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType; import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA; import cn.hutool.crypto.asymmetric.RSA;
@ -15,28 +14,24 @@ import com.ruoyi.common.utils.StringUtils;
* RSA算法实现 * RSA算法实现
* *
* @author 老马 * @author 老马
* @date 2023-01-06 09:37 * @version 4.6.0
*/ */
public class RsaEncryptor extends AbstractEncryptor { public class RsaEncryptor extends AbstractEncryptor {
private RSA rsa = null; private final RSA rsa;
public RsaEncryptor(EncryptContext context) { public RsaEncryptor(EncryptContext context) {
super(context); super(context);
String privateKey = context.getPrivateKey(); String privateKey = context.getPrivateKey();
String publicKey = context.getPublicKey(); String publicKey = context.getPublicKey();
if (StringUtils.isAnyEmpty(privateKey, publicKey)) { if (StringUtils.isAnyEmpty(privateKey, publicKey)) {
throw new RuntimeException("rsa公私钥均需要提供,公钥加密,私钥解密。"); throw new IllegalArgumentException("RSA公私钥均需要提供,公钥加密,私钥解密。");
} }
this.rsa = SecureUtil.rsa(Base64.decode(privateKey), Base64.decode(publicKey)); this.rsa = SecureUtil.rsa(Base64.decode(privateKey), Base64.decode(publicKey));
} }
/** /**
* 获得当前算法 * 获得当前算法
*
* @return com.ruoyi.common.enums.AlgorithmType
* @author 老马
* @date 2023/1/11 11:18
*/ */
@Override @Override
public AlgorithmType algorithm() { public AlgorithmType algorithm() {
@ -48,36 +43,23 @@ public class RsaEncryptor extends AbstractEncryptor {
* *
* @param value 待加密字符串 * @param value 待加密字符串
* @param encodeType 加密后的编码格式 * @param encodeType 加密后的编码格式
* @return java.lang.String
* @author 老马
* @date 2023/1/10 16:38
*/ */
@Override @Override
public String encrypt(String value, EncodeType encodeType) throws Exception { public String encrypt(String value, EncodeType encodeType) {
if (ObjectUtil.isNotNull(this.rsa)) { if (encodeType == EncodeType.HEX) {
if (encodeType == EncodeType.HEX) { return rsa.encryptHex(value, KeyType.PublicKey);
return rsa.encryptHex(value, KeyType.PublicKey); } else {
} else { return rsa.encryptBase64(value, KeyType.PublicKey);
return rsa.encryptBase64(value, KeyType.PublicKey);
}
} }
return value;
} }
/** /**
* 解密 * 解密
* *
* @param value 待加密字符串 * @param value 待加密字符串
* @param encodeType 加密后的编码格式
* @return java.lang.String
* @author 老马
* @date 2023/1/10 16:38
*/ */
@Override @Override
public String decrypt(String value, EncodeType encodeType) throws Exception { public String decrypt(String value) {
if (ObjectUtil.isNotNull(this.rsa)) { return this.rsa.decryptStr(value, KeyType.PrivateKey);
return this.rsa.decryptStr(value, KeyType.PrivateKey);
}
return value;
} }
} }

View File

@ -2,7 +2,6 @@ package com.ruoyi.common.encrypt.encryptor;
import cn.hutool.core.codec.Base64; import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.SmUtil; import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType; import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2; import cn.hutool.crypto.asymmetric.SM2;
@ -15,28 +14,24 @@ import com.ruoyi.common.utils.StringUtils;
* sm2算法实现 * sm2算法实现
* *
* @author 老马 * @author 老马
* @date 2023-01-06 17:13 * @version 4.6.0
*/ */
public class Sm2Encryptor extends AbstractEncryptor { public class Sm2Encryptor extends AbstractEncryptor {
private SM2 sm2 = null; private final SM2 sm2;
public Sm2Encryptor(EncryptContext context) { public Sm2Encryptor(EncryptContext context) {
super(context); super(context);
String privateKey = context.getPrivateKey(); String privateKey = context.getPrivateKey();
String publicKey = context.getPublicKey(); String publicKey = context.getPublicKey();
if (StringUtils.isAnyEmpty(privateKey, publicKey)) { if (StringUtils.isAnyEmpty(privateKey, publicKey)) {
throw new RuntimeException("sm2公私钥均需要提供公钥加密私钥解密。"); throw new IllegalArgumentException("SM2公私钥均需要提供公钥加密私钥解密。");
} }
this.sm2 = SmUtil.sm2(Base64.decode(privateKey), Base64.decode(publicKey)); this.sm2 = SmUtil.sm2(Base64.decode(privateKey), Base64.decode(publicKey));
} }
/** /**
* 获得当前算法 * 获得当前算法
*
* @return com.ruoyi.common.enums.AlgorithmType
* @author 老马
* @date 2023/1/11 11:18
*/ */
@Override @Override
public AlgorithmType algorithm() { public AlgorithmType algorithm() {
@ -48,38 +43,23 @@ public class Sm2Encryptor extends AbstractEncryptor {
* *
* @param value 待加密字符串 * @param value 待加密字符串
* @param encodeType 加密后的编码格式 * @param encodeType 加密后的编码格式
* @return java.lang.String
* @throws Exception 抛出异常
* @author 老马
* @date 2023/1/10 16:38
*/ */
@Override @Override
public String encrypt(String value, EncodeType encodeType) throws Exception { public String encrypt(String value, EncodeType encodeType) {
if (ObjectUtil.isNotNull(this.sm2)) { if (encodeType == EncodeType.HEX) {
if (encodeType == EncodeType.HEX) { return sm2.encryptHex(value, KeyType.PublicKey);
return sm2.encryptHex(value, KeyType.PublicKey); } else {
} else { return sm2.encryptBase64(value, KeyType.PublicKey);
return sm2.encryptBase64(value, KeyType.PublicKey);
}
} }
return value;
} }
/** /**
* 解密 * 解密
* *
* @param value 待加密字符串 * @param value 待加密字符串
* @param encodeType 加密后的编码格式
* @return java.lang.String
* @throws Exception 抛出异常
* @author 老马
* @date 2023/1/10 16:38
*/ */
@Override @Override
public String decrypt(String value, EncodeType encodeType) throws Exception { public String decrypt(String value) {
if (ObjectUtil.isNotNull(this.sm2)) { return this.sm2.decryptStr(value, KeyType.PrivateKey);
return this.sm2.decryptStr(value, KeyType.PrivateKey);
}
return value;
} }
} }

View File

@ -1,6 +1,5 @@
package com.ruoyi.common.encrypt.encryptor; package com.ruoyi.common.encrypt.encryptor;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SmUtil; import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.symmetric.SM4; import cn.hutool.crypto.symmetric.SM4;
@ -14,31 +13,27 @@ import java.nio.charset.StandardCharsets;
* sm4算法实现 * sm4算法实现
* *
* @author 老马 * @author 老马
* @date 2023-01-06 17:40 * @version 4.6.0
*/ */
public class Sm4Encryptor extends AbstractEncryptor { public class Sm4Encryptor extends AbstractEncryptor {
private SM4 sm4 = null; private final SM4 sm4;
public Sm4Encryptor(EncryptContext context) { public Sm4Encryptor(EncryptContext context) {
super(context); super(context);
String password = context.getPassword(); String password = context.getPassword();
if (StrUtil.isBlank(password)) { if (StrUtil.isBlank(password)) {
throw new RuntimeException("sm4没有获得秘钥信息"); throw new IllegalArgumentException("SM4没有获得秘钥信息");
} }
// sm4算法的秘钥要求是16位长度 // sm4算法的秘钥要求是16位长度
if (16 != password.length()) { if (16 != password.length()) {
throw new RuntimeException("sm4秘钥长度应该为16位实际为" + password.length() + ""); throw new IllegalArgumentException("SM4秘钥长度应该为16位实际为" + password.length() + "");
} }
this.sm4 = SmUtil.sm4(password.getBytes(StandardCharsets.UTF_8)); this.sm4 = SmUtil.sm4(password.getBytes(StandardCharsets.UTF_8));
} }
/** /**
* 获得当前算法 * 获得当前算法
*
* @return com.ruoyi.common.enums.AlgorithmType
* @author 老马
* @date 2023/1/11 11:18
*/ */
@Override @Override
public AlgorithmType algorithm() { public AlgorithmType algorithm() {
@ -50,38 +45,23 @@ public class Sm4Encryptor extends AbstractEncryptor {
* *
* @param value 待加密字符串 * @param value 待加密字符串
* @param encodeType 加密后的编码格式 * @param encodeType 加密后的编码格式
* @return java.lang.String
* @throws Exception 抛出异常
* @author 老马
* @date 2023/1/10 16:38
*/ */
@Override @Override
public String encrypt(String value, EncodeType encodeType) throws Exception { public String encrypt(String value, EncodeType encodeType) {
if (ObjectUtil.isNotNull(this.sm4)) { if (encodeType == EncodeType.HEX) {
if (encodeType == EncodeType.HEX) { return sm4.encryptHex(value);
return sm4.encryptHex(value); } else {
} else { return sm4.encryptBase64(value);
return sm4.encryptBase64(value);
}
} }
return value;
} }
/** /**
* 解密 * 解密
* *
* @param value 待加密字符串 * @param value 待加密字符串
* @param encodeType 加密后的编码格式
* @return java.lang.String
* @throws Exception 抛出异常
* @author 老马
* @date 2023/1/10 16:38
*/ */
@Override @Override
public String decrypt(String value, EncodeType encodeType) throws Exception { public String decrypt(String value) {
if (ObjectUtil.isNotNull(this.sm4)) { return this.sm4.decryptStr(value);
return this.sm4.decryptStr(value);
}
return value;
} }
} }

View File

@ -1,6 +1,5 @@
package com.ruoyi.common.enums; package com.ruoyi.common.enums;
import com.ruoyi.common.encrypt.IEncryptor;
import com.ruoyi.common.encrypt.encryptor.*; import com.ruoyi.common.encrypt.encryptor.*;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
@ -9,10 +8,17 @@ import lombok.Getter;
* 算法名称 * 算法名称
* *
* @author 老马 * @author 老马
* @version 4.6.0
*/ */
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
public enum AlgorithmType { public enum AlgorithmType {
/**
* 默认走yml配置
*/
DEFAULT(null),
/** /**
* base64 * base64
*/ */
@ -38,5 +44,5 @@ public enum AlgorithmType {
*/ */
SM4(Sm4Encryptor.class); SM4(Sm4Encryptor.class);
private final Class<? extends IEncryptor> clazz; private final Class<? extends AbstractEncryptor> clazz;
} }

View File

@ -4,9 +4,15 @@ package com.ruoyi.common.enums;
* 编码类型 * 编码类型
* *
* @author 老马 * @author 老马
* @date 2023-01-11 11:39 * @version 4.6.0
*/ */
public enum EncodeType { public enum EncodeType {
/**
* 默认使用yml配置
*/
DEFAULT,
/** /**
* base64编码 * base64编码
*/ */

View File

@ -0,0 +1,55 @@
package com.ruoyi.demo.controller;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.demo.domain.TestDemoEncrypt;
import com.ruoyi.demo.mapper.TestDemoEncryptMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
/**
* 测试数据库加解密功能
*
* @author Lion Li
*/
@Validated
@RestController
@RequestMapping("/demo/encrypt")
public class TestEncryptController {
@Autowired
private TestDemoEncryptMapper mapper;
@Value("${mybatis-encryptor.enable}")
private Boolean encryptEnable;
/**
* 测试数据库加解密
*
* @param key 测试key
* @param value 测试value
*/
@GetMapping()
public R<Map<String, TestDemoEncrypt>> test(String key, String value) {
if (!encryptEnable) {
throw new RuntimeException("加密功能未开启!");
}
Map<String, TestDemoEncrypt> map = new HashMap<>(2);
TestDemoEncrypt demo = new TestDemoEncrypt();
demo.setTestKey(key);
demo.setValue(value);
mapper.insert(demo);
map.put("加密", demo);
TestDemoEncrypt testDemo = mapper.selectById(demo.getId());
map.put("解密", testDemo);
return R.ok(map);
}
}

View File

@ -1,9 +1,7 @@
package com.ruoyi.demo.domain; package com.ruoyi.demo.domain;
import com.baomidou.mybatisplus.annotation.*; import com.baomidou.mybatisplus.annotation.*;
import com.ruoyi.common.annotation.EncryptField;
import com.ruoyi.common.core.domain.BaseEntity; import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.common.enums.AlgorithmType;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@ -46,15 +44,11 @@ public class TestDemo extends BaseEntity {
/** /**
* key键 * key键
*/ */
// @EncryptField(algorithm=AlgorithmType.SM2, privateKey = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgZSlOvw8FBiH+aFJWLYZP/VRjg9wjfRarTkGBZd/T3N+gCgYIKoEcz1UBgi2hRANCAAR5DGuQwJqkxnbCsP+iPSDoHWIF4RwcR5EsSvT8QPxO1wRkR2IhCkzvRb32x2CUgJFdvoqVqfApFDPZzShqzBwX", publicKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEeQxrkMCapMZ2wrD/oj0g6B1iBeEcHEeRLEr0/ED8TtcEZEdiIQpM70W99sdglICRXb6KlanwKRQz2c0oaswcFw==")
@EncryptField(algorithm = AlgorithmType.RSA, privateKey = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBANBBEeueWlXlkkj2+WY5l+IWe42d8b5K28g+G/CFKC/yYAEHtqGlCsBOrb+YBkG9mPzmuYA/n9k0NFIc8E8yY5vZQaroyFBrTTWEzG9RY2f7Y3svVyybs6jpXSUs4xff8abo7wL1Y/wUaeatTViamxYnyTvdTmLm3d+JjRij68rxAgMBAAECgYAB0TnhXraSopwIVRfmboea1b0upl+BUdTJcmci412UjrKr5aE695ZLPkXbFXijVu7HJlyyv94NVUdaMACV7Ku/S2RuNB70M7YJm8rAjHFC3/i2ZeIM60h1Ziy4QKv0XM3pRATlDCDNhC1WUrtQCQSgU8kcp6eUUppruOqDzcY04QJBAPm9+sBP9CwDRgy3e5+V8aZtJkwDstb0lVVV/KY890cydVxiCwvX3fqVnxKMlb+x0YtH0sb9v+71xvK2lGobaRECQQDVePU6r/cCEfpc+nkWF6osAH1f8Mux3rYv2DoBGvaPzV2BGfsLed4neRfCwWNCKvGPCdW+L0xMJg8+RwaoBUPhAkAT5kViqXxFPYWJYd1h2+rDXhMdH3ZSlm6HvDBDdrwlWinr0Iwcx3iSjPV93uHXwm118aUj4fg3LDJMCKxOwBxhAkByrQXfvwOMYygBprRBf/j0plazoWFrbd6lGR0f1uI5IfNnFRPdeFw1DEINZ2Hw+6zEUF44SqRMC+4IYJNc02dBAkBCgy7RvfyV/A7N6kKXxTHauY0v6XwSSvpeKtRJkbIcRWOdIYvaHO9L7cklj3vIEdwjSUp9K4VTBYYlmAz1xh03", publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQQRHrnlpV5ZJI9vlmOZfiFnuNnfG+StvIPhvwhSgv8mABB7ahpQrATq2/mAZBvZj85rmAP5/ZNDRSHPBPMmOb2UGq6MhQa001hMxvUWNn+2N7L1csm7Oo6V0lLOMX3/Gm6O8C9WP8FGnmrU1YmpsWJ8k73U5i5t3fiY0Yo+vK8QIDAQAB")
private String testKey; private String testKey;
/** /**
* *
*/ */
//@EncryptField(algorithm = AlgorithmType.SM4, password = "10rfylhtccpuyke5")
@EncryptField(algorithm = AlgorithmType.AES, password = "10rfylhtccpuyke5")
private String value; private String value;
/** /**

View File

@ -0,0 +1,29 @@
package com.ruoyi.demo.domain;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.annotation.EncryptField;
import com.ruoyi.common.enums.AlgorithmType;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("test_demo")
public class TestDemoEncrypt extends TestDemo {
/**
* key键
*/
// @EncryptField(algorithm=AlgorithmType.SM2, privateKey = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgZSlOvw8FBiH+aFJWLYZP/VRjg9wjfRarTkGBZd/T3N+gCgYIKoEcz1UBgi2hRANCAAR5DGuQwJqkxnbCsP+iPSDoHWIF4RwcR5EsSvT8QPxO1wRkR2IhCkzvRb32x2CUgJFdvoqVqfApFDPZzShqzBwX", publicKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEeQxrkMCapMZ2wrD/oj0g6B1iBeEcHEeRLEr0/ED8TtcEZEdiIQpM70W99sdglICRXb6KlanwKRQz2c0oaswcFw==")
@EncryptField(algorithm = AlgorithmType.RSA, privateKey = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBANBBEeueWlXlkkj2+WY5l+IWe42d8b5K28g+G/CFKC/yYAEHtqGlCsBOrb+YBkG9mPzmuYA/n9k0NFIc8E8yY5vZQaroyFBrTTWEzG9RY2f7Y3svVyybs6jpXSUs4xff8abo7wL1Y/wUaeatTViamxYnyTvdTmLm3d+JjRij68rxAgMBAAECgYAB0TnhXraSopwIVRfmboea1b0upl+BUdTJcmci412UjrKr5aE695ZLPkXbFXijVu7HJlyyv94NVUdaMACV7Ku/S2RuNB70M7YJm8rAjHFC3/i2ZeIM60h1Ziy4QKv0XM3pRATlDCDNhC1WUrtQCQSgU8kcp6eUUppruOqDzcY04QJBAPm9+sBP9CwDRgy3e5+V8aZtJkwDstb0lVVV/KY890cydVxiCwvX3fqVnxKMlb+x0YtH0sb9v+71xvK2lGobaRECQQDVePU6r/cCEfpc+nkWF6osAH1f8Mux3rYv2DoBGvaPzV2BGfsLed4neRfCwWNCKvGPCdW+L0xMJg8+RwaoBUPhAkAT5kViqXxFPYWJYd1h2+rDXhMdH3ZSlm6HvDBDdrwlWinr0Iwcx3iSjPV93uHXwm118aUj4fg3LDJMCKxOwBxhAkByrQXfvwOMYygBprRBf/j0plazoWFrbd6lGR0f1uI5IfNnFRPdeFw1DEINZ2Hw+6zEUF44SqRMC+4IYJNc02dBAkBCgy7RvfyV/A7N6kKXxTHauY0v6XwSSvpeKtRJkbIcRWOdIYvaHO9L7cklj3vIEdwjSUp9K4VTBYYlmAz1xh03", publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQQRHrnlpV5ZJI9vlmOZfiFnuNnfG+StvIPhvwhSgv8mABB7ahpQrATq2/mAZBvZj85rmAP5/ZNDRSHPBPMmOb2UGq6MhQa001hMxvUWNn+2N7L1csm7Oo6V0lLOMX3/Gm6O8C9WP8FGnmrU1YmpsWJ8k73U5i5t3fiY0Yo+vK8QIDAQAB")
private String testKey;
/**
*
*/
// @EncryptField // 什么也不写走默认yml配置
// @EncryptField(algorithm = AlgorithmType.SM4, password = "10rfylhtccpuyke5")
@EncryptField(algorithm = AlgorithmType.AES, password = "10rfylhtccpuyke5")
private String value;
}

View File

@ -0,0 +1,13 @@
package com.ruoyi.demo.mapper;
import com.ruoyi.common.core.mapper.BaseMapperPlus;
import com.ruoyi.demo.domain.TestDemoEncrypt;
/**
* 测试加密功能
*
* @author Lion Li
*/
public interface TestDemoEncryptMapper extends BaseMapperPlus<TestDemoEncryptMapper, TestDemoEncrypt, TestDemoEncrypt> {
}

View File

@ -1,9 +1,10 @@
package com.ruoyi.framework.config; package com.ruoyi.framework.config;
import com.ruoyi.framework.config.properties.EncryptorProperties; import com.ruoyi.framework.config.properties.EncryptorProperties;
import com.ruoyi.framework.encrypt.EncryptorManager; import com.ruoyi.framework.manager.EncryptorManager;
import com.ruoyi.framework.encrypt.MybatisDecryptInterceptor; import com.ruoyi.framework.encrypt.MybatisDecryptInterceptor;
import com.ruoyi.framework.encrypt.MybatisEncryptInterceptor; import com.ruoyi.framework.encrypt.MybatisEncryptInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -12,26 +13,27 @@ import org.springframework.context.annotation.Configuration;
* 加解密配置 * 加解密配置
* *
* @author 老马 * @author 老马
* @date 2023-01-11 10:03 * @version 4.6.0
*/ */
@Configuration @Configuration
@ConditionalOnProperty(value = "mybatis-encryptor.enabled", havingValue = "true") @ConditionalOnProperty(value = "mybatis-encryptor.enable", havingValue = "true")
public class EncryptorConfig { public class EncryptorConfig {
@Autowired
private EncryptorProperties properties;
@Bean @Bean
public EncryptorManager mybatisCryptHandler(EncryptorProperties properties) { public EncryptorManager encryptorManager() {
EncryptorManager encryptorManager = new EncryptorManager(); return new EncryptorManager();
encryptorManager.registAndGetEncryptor(properties);
return encryptorManager;
} }
@Bean @Bean
public MybatisEncryptInterceptor mybatisEncryptInterceptor(EncryptorProperties properties) { public MybatisEncryptInterceptor mybatisEncryptInterceptor(EncryptorManager encryptorManager) {
return new MybatisEncryptInterceptor(); return new MybatisEncryptInterceptor(encryptorManager, properties);
} }
@Bean @Bean
public MybatisDecryptInterceptor mybatisDecryptInterceptor(EncryptorProperties properties) { public MybatisDecryptInterceptor mybatisDecryptInterceptor(EncryptorManager encryptorManager) {
return new MybatisDecryptInterceptor(); return new MybatisDecryptInterceptor(encryptorManager, properties);
} }
} }

View File

@ -10,7 +10,7 @@ import org.springframework.stereotype.Component;
* 加解密属性配置类 * 加解密属性配置类
* *
* @author 老马 * @author 老马
* @date 2023-01-10 16:52 * @version 4.6.0
*/ */
@Data @Data
@Component @Component
@ -20,7 +20,7 @@ public class EncryptorProperties {
/** /**
* 过滤开关 * 过滤开关
*/ */
private Boolean enabled; private Boolean enable;
/** /**
* 默认算法 * 默认算法
@ -46,4 +46,5 @@ public class EncryptorProperties {
* 编码方式base64/hex * 编码方式base64/hex
*/ */
private EncodeType encode; private EncodeType encode;
} }

View File

@ -1,33 +0,0 @@
package com.ruoyi.framework.encrypt;
import com.ruoyi.common.annotation.EncryptField;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
/**
* 类加密字段缓存类
*
* @author 老马
* @date 2023-01-12 11:07
*/
public class EncryptedFieldsCache {
private static final Map<Class<?>, Set<Field>> ENCRYPTED_FIELD_CACHE = new ConcurrentHashMap<>();
public static Set<Field> get(Class<?> sourceClazz) {
return ENCRYPTED_FIELD_CACHE.computeIfAbsent(sourceClazz, clazz -> {
Field[] declaredFields = clazz.getDeclaredFields();
Set<Field> fieldSet = Arrays.stream(declaredFields).filter(field ->
field.isAnnotationPresent(EncryptField.class) && field.getType() == String.class)
.collect(Collectors.toSet());
for (Field field : fieldSet) {
field.setAccessible(true);
}
return fieldSet;
});
}
}

View File

@ -1,120 +0,0 @@
package com.ruoyi.framework.encrypt;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import com.ruoyi.common.encrypt.EncryptContext;
import com.ruoyi.common.encrypt.IEncryptor;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.config.properties.EncryptorProperties;
import lombok.extern.slf4j.Slf4j;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 加密管理类
*
* @author 老马
* @date 2023-01-11 10:07
*/
@Slf4j
public class EncryptorManager {
/**
* 缓存加密器
*/
Map<String, IEncryptor> encryptorMap = new ConcurrentHashMap<>();
/**
* 注册加密执行者到缓存
*
* @param properties 加密执行者需要的相关配置参数
* @author 老马
* @date 2023/1/11 15:09
*/
public IEncryptor registAndGetEncryptor(EncryptorProperties properties) {
String encryptorKey = this.getEncryptorKeyFromProperties(properties);
if (encryptorMap.containsKey(encryptorKey)) {
return encryptorMap.get(encryptorKey);
}
EncryptContext encryptContext = new EncryptContext();
encryptContext.setPassword(properties.getPassword());
encryptContext.setPrivateKey(properties.getPrivateKey());
encryptContext.setPublicKey(properties.getPublicKey());
encryptContext.setEncode(properties.getEncode());
IEncryptor encryptor = ReflectUtil.newInstance(properties.getAlgorithm().getClazz(), encryptContext);
encryptorMap.put(encryptorKey, encryptor);
return encryptorMap.get(encryptorKey);
}
/**
* 移除缓存中的加密执行者
*
* @param properties 加密执行者需要的相关配置参数
* @author 老马
* @date 2023/1/11 15:55
*/
public void removeEncryptor(EncryptorProperties properties) {
this.encryptorMap.remove(getEncryptorKeyFromProperties(properties));
}
/**
* 根据配置进行加密会进行本地缓存对应的算法和对应的秘钥信息
*
* @param value 待加密的值
* @param properties 加密相关的配置信息
* @return java.lang.String 加密后的结果
* @author 老马
* @date 2023/1/11 16:46
*/
public String encrypt(String value, EncryptorProperties properties) {
try {
IEncryptor encryptor = this.registAndGetEncryptor(properties);
if(ObjectUtil.isNull(encryptor)){
return value;
}
return encryptor.encrypt(value, properties.getEncode());
} catch (Exception e) {
log.error("字段加密异常,原样返回", e);
return value;
}
}
/**
* 根据配置进行解密
*
* @param value 待解密的值
* @param properties 加密相关的配置信息
* @return java.lang.String
* @author 老马
* @date 2023/1/11 17:43
*/
public String decrypt(String value, EncryptorProperties properties) {
try {
IEncryptor encryptor = this.registAndGetEncryptor(properties);
if(ObjectUtil.isNull(encryptor)){
return value;
}
return encryptor.decrypt(value, properties.getEncode());
} catch (Exception e) {
log.error("字段解密异常,原样返回", e);
return value;
}
}
/**
* 从配置内容中提取缓存的KEY
*
* @param properties 加密相关的配置信息
* @return java.lang.String
* @author 老马
* @date 2023/1/11 17:39
*/
private String getEncryptorKeyFromProperties(EncryptorProperties properties) {
return properties.getAlgorithm() + StringUtils.defaultString(properties.getPassword()) +
StringUtils.defaultString(properties.getPublicKey()) + StringUtils.defaultString(properties.getPrivateKey());
}
}

View File

@ -2,9 +2,13 @@ package com.ruoyi.framework.encrypt;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import com.ruoyi.common.annotation.EncryptField; import com.ruoyi.common.annotation.EncryptField;
import com.ruoyi.common.encrypt.EncryptContext;
import com.ruoyi.common.enums.AlgorithmType;
import com.ruoyi.common.enums.EncodeType;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.framework.config.properties.EncryptorProperties; import com.ruoyi.framework.config.properties.EncryptorProperties;
import com.ruoyi.framework.manager.EncryptorManager;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.resultset.ResultSetHandler; import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.plugin.*; import org.apache.ibatis.plugin.*;
@ -20,7 +24,7 @@ import java.util.Set;
* 出参解密拦截器 * 出参解密拦截器
* *
* @author 老马 * @author 老马
* @date 2023-01-12 13:47 * @version 4.6.0
*/ */
@Slf4j @Slf4j
@Intercepts({@Signature( @Intercepts({@Signature(
@ -28,10 +32,11 @@ import java.util.Set;
method = "handleResultSets", method = "handleResultSets",
args = {Statement.class}) args = {Statement.class})
}) })
@AllArgsConstructor
public class MybatisDecryptInterceptor implements Interceptor { public class MybatisDecryptInterceptor implements Interceptor {
private final EncryptorManager encryptorManager = SpringUtils.getBean(EncryptorManager.class); private final EncryptorManager encryptorManager;
private final EncryptorProperties defaultProperties = SpringUtils.getBean(EncryptorProperties.class); private final EncryptorProperties defaultProperties;
@Override @Override
public Object intercept(Invocation invocation) throws Throwable { public Object intercept(Invocation invocation) throws Throwable {
@ -57,13 +62,13 @@ public class MybatisDecryptInterceptor implements Interceptor {
if (sourceObject instanceof List) { if (sourceObject instanceof List) {
// 判断第一个元素是否含有注解如果没有直接返回提高效率 // 判断第一个元素是否含有注解如果没有直接返回提高效率
Object firstItem = ((List<?>) sourceObject).get(0); Object firstItem = ((List<?>) sourceObject).get(0);
if (CollectionUtil.isEmpty(EncryptedFieldsCache.get(firstItem.getClass()))) { if (CollectionUtil.isEmpty(encryptorManager.getFieldCache(firstItem.getClass()))) {
return; return;
} }
((List<?>) sourceObject).forEach(this::decryptHandler); ((List<?>) sourceObject).forEach(this::decryptHandler);
return; return;
} }
Set<Field> fields = EncryptedFieldsCache.get(sourceObject.getClass()); Set<Field> fields = encryptorManager.getFieldCache(sourceObject.getClass());
try { try {
for (Field field : fields) { for (Field field : fields) {
field.set(sourceObject, this.decryptField(String.valueOf(field.get(sourceObject)), field)); field.set(sourceObject, this.decryptField(String.valueOf(field.get(sourceObject)), field));
@ -82,15 +87,13 @@ public class MybatisDecryptInterceptor implements Interceptor {
*/ */
private String decryptField(String value, Field field) { private String decryptField(String value, Field field) {
EncryptField encryptField = field.getAnnotation(EncryptField.class); EncryptField encryptField = field.getAnnotation(EncryptField.class);
EncryptorProperties properties = new EncryptorProperties(); EncryptContext encryptContext = new EncryptContext();
properties.setEnabled(true); encryptContext.setAlgorithm(encryptField.algorithm() == AlgorithmType.DEFAULT ? defaultProperties.getAlgorithm() : encryptField.algorithm());
properties.setAlgorithm(encryptField.algorithm()); encryptContext.setEncode(encryptField.encode() == EncodeType.DEFAULT ? defaultProperties.getEncode() : encryptField.encode());
properties.setEncode(encryptField.encode()); encryptContext.setPassword(StringUtils.isBlank(encryptField.password()) ? defaultProperties.getPassword() : encryptField.password());
properties.setPassword(StringUtils.isEmpty(encryptField.password()) ? defaultProperties.getPassword() : encryptField.password()); encryptContext.setPrivateKey(StringUtils.isBlank(encryptField.privateKey()) ? defaultProperties.getPrivateKey() : encryptField.privateKey());
properties.setPrivateKey(StringUtils.isEmpty(encryptField.privateKey()) ? defaultProperties.getPrivateKey() : encryptField.privateKey()); encryptContext.setPublicKey(StringUtils.isBlank(encryptField.publicKey()) ? defaultProperties.getPublicKey() : encryptField.publicKey());
properties.setPublicKey(StringUtils.isEmpty(encryptField.publicKey()) ? defaultProperties.getPublicKey() : encryptField.publicKey()); return this.encryptorManager.decrypt(value, encryptContext);
this.encryptorManager.registAndGetEncryptor(properties);
return this.encryptorManager.decrypt(value, properties);
} }
@Override @Override

View File

@ -3,9 +3,13 @@ package com.ruoyi.framework.encrypt;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.ruoyi.common.annotation.EncryptField; import com.ruoyi.common.annotation.EncryptField;
import com.ruoyi.common.encrypt.EncryptContext;
import com.ruoyi.common.enums.AlgorithmType;
import com.ruoyi.common.enums.EncodeType;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.framework.config.properties.EncryptorProperties; import com.ruoyi.framework.config.properties.EncryptorProperties;
import com.ruoyi.framework.manager.EncryptorManager;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.parameter.ParameterHandler; import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.plugin.Interceptor; import org.apache.ibatis.plugin.Interceptor;
@ -24,7 +28,7 @@ import java.util.Set;
* 入参加密拦截器 * 入参加密拦截器
* *
* @author 老马 * @author 老马
* @date 2023-01-10 16:42 * @version 4.6.0
*/ */
@Slf4j @Slf4j
@Intercepts({@Signature( @Intercepts({@Signature(
@ -32,10 +36,11 @@ import java.util.Set;
method = "setParameters", method = "setParameters",
args = {PreparedStatement.class}) args = {PreparedStatement.class})
}) })
@AllArgsConstructor
public class MybatisEncryptInterceptor implements Interceptor { public class MybatisEncryptInterceptor implements Interceptor {
private final EncryptorManager encryptorManager = SpringUtils.getBean(EncryptorManager.class); private final EncryptorManager encryptorManager;
private final EncryptorProperties defaultProperties = SpringUtils.getBean(EncryptorProperties.class); private final EncryptorProperties defaultProperties;
@Override @Override
public Object intercept(Invocation invocation) throws Throwable { public Object intercept(Invocation invocation) throws Throwable {
@ -60,6 +65,7 @@ public class MybatisEncryptInterceptor implements Interceptor {
* *
* @param sourceObject 待加密对象 * @param sourceObject 待加密对象
*/ */
@SuppressWarnings("unchecked cast")
private void encryptHandler(Object sourceObject) { private void encryptHandler(Object sourceObject) {
if (sourceObject instanceof Map) { if (sourceObject instanceof Map) {
((Map<?, Object>) sourceObject).values().forEach(this::encryptHandler); ((Map<?, Object>) sourceObject).values().forEach(this::encryptHandler);
@ -68,13 +74,13 @@ public class MybatisEncryptInterceptor implements Interceptor {
if (sourceObject instanceof List) { if (sourceObject instanceof List) {
// 判断第一个元素是否含有注解如果没有直接返回提高效率 // 判断第一个元素是否含有注解如果没有直接返回提高效率
Object firstItem = ((List<?>) sourceObject).get(0); Object firstItem = ((List<?>) sourceObject).get(0);
if (CollectionUtil.isEmpty(EncryptedFieldsCache.get(firstItem.getClass()))) { if (CollectionUtil.isEmpty(encryptorManager.getFieldCache(firstItem.getClass()))) {
return; return;
} }
((List<?>) sourceObject).forEach(this::encryptHandler); ((List<?>) sourceObject).forEach(this::encryptHandler);
return; return;
} }
Set<Field> fields = EncryptedFieldsCache.get(sourceObject.getClass()); Set<Field> fields = encryptorManager.getFieldCache(sourceObject.getClass());
try { try {
for (Field field : fields) { for (Field field : fields) {
field.set(sourceObject, this.encryptField(String.valueOf(field.get(sourceObject)), field)); field.set(sourceObject, this.encryptField(String.valueOf(field.get(sourceObject)), field));
@ -93,15 +99,13 @@ public class MybatisEncryptInterceptor implements Interceptor {
*/ */
private String encryptField(String value, Field field) { private String encryptField(String value, Field field) {
EncryptField encryptField = field.getAnnotation(EncryptField.class); EncryptField encryptField = field.getAnnotation(EncryptField.class);
EncryptorProperties properties = new EncryptorProperties(); EncryptContext encryptContext = new EncryptContext();
properties.setEnabled(true); encryptContext.setAlgorithm(encryptField.algorithm() == AlgorithmType.DEFAULT ? defaultProperties.getAlgorithm() : encryptField.algorithm());
properties.setAlgorithm(encryptField.algorithm()); encryptContext.setEncode(encryptField.encode() == EncodeType.DEFAULT ? defaultProperties.getEncode() : encryptField.encode());
properties.setEncode(encryptField.encode()); encryptContext.setPassword(StringUtils.isBlank(encryptField.password()) ? defaultProperties.getPassword() : encryptField.password());
properties.setPassword(StringUtils.isEmpty(encryptField.password()) ? defaultProperties.getPassword() : encryptField.password()); encryptContext.setPrivateKey(StringUtils.isBlank(encryptField.privateKey()) ? defaultProperties.getPrivateKey() : encryptField.privateKey());
properties.setPrivateKey(StringUtils.isEmpty(encryptField.privateKey()) ? defaultProperties.getPrivateKey() : encryptField.privateKey()); encryptContext.setPublicKey(StringUtils.isBlank(encryptField.publicKey()) ? defaultProperties.getPublicKey() : encryptField.publicKey());
properties.setPublicKey(StringUtils.isEmpty(encryptField.publicKey()) ? defaultProperties.getPublicKey() : encryptField.publicKey()); return this.encryptorManager.encrypt(value, encryptContext);
this.encryptorManager.registAndGetEncryptor(properties);
return this.encryptorManager.encrypt(value, properties);
} }

View File

@ -0,0 +1,96 @@
package com.ruoyi.framework.manager;
import cn.hutool.core.util.ReflectUtil;
import com.ruoyi.common.annotation.EncryptField;
import com.ruoyi.common.encrypt.EncryptContext;
import com.ruoyi.common.encrypt.IEncryptor;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
/**
* 加密管理类
*
* @author 老马
* @version 4.6.0
*/
@Slf4j
public class EncryptorManager {
/**
* 缓存加密器
*/
Map<EncryptContext, IEncryptor> encryptorMap = new ConcurrentHashMap<>();
/**
* 类加密字段缓存
*/
Map<Class<?>, Set<Field>> fieldCache = new ConcurrentHashMap<>();
/**
* 获取类加密字段缓存
*/
public Set<Field> getFieldCache(Class<?> sourceClazz) {
return fieldCache.computeIfAbsent(sourceClazz, clazz -> {
Field[] declaredFields = clazz.getDeclaredFields();
Set<Field> fieldSet = Arrays.stream(declaredFields).filter(field ->
field.isAnnotationPresent(EncryptField.class) && field.getType() == String.class)
.collect(Collectors.toSet());
for (Field field : fieldSet) {
field.setAccessible(true);
}
return fieldSet;
});
}
/**
* 注册加密执行者到缓存
*
* @param encryptContext 加密执行者需要的相关配置参数
*/
public IEncryptor registAndGetEncryptor(EncryptContext encryptContext) {
if (encryptorMap.containsKey(encryptContext)) {
return encryptorMap.get(encryptContext);
}
IEncryptor encryptor = ReflectUtil.newInstance(encryptContext.getAlgorithm().getClazz(), encryptContext);
encryptorMap.put(encryptContext, encryptor);
return encryptor;
}
/**
* 移除缓存中的加密执行者
*
* @param encryptContext 加密执行者需要的相关配置参数
*/
public void removeEncryptor(EncryptContext encryptContext) {
this.encryptorMap.remove(encryptContext);
}
/**
* 根据配置进行加密会进行本地缓存对应的算法和对应的秘钥信息
*
* @param value 待加密的值
* @param encryptContext 加密相关的配置信息
*/
public String encrypt(String value, EncryptContext encryptContext) {
IEncryptor encryptor = this.registAndGetEncryptor(encryptContext);
return encryptor.encrypt(value, encryptContext.getEncode());
}
/**
* 根据配置进行解密
*
* @param value 待解密的值
* @param encryptContext 加密相关的配置信息
*/
public String decrypt(String value, EncryptContext encryptContext) {
IEncryptor encryptor = this.registAndGetEncryptor(encryptContext);
return encryptor.decrypt(value);
}
}