From c59122a194edbeb58a3a9e5eb4d0142e6202f447 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90li?=
<15040126243@163.com>
Date: Sun, 5 Feb 2023 15:12:55 +0800
Subject: [PATCH] =?UTF-8?q?add=20=E6=96=B0=E5=A2=9E=20=E8=BF=81=E7=A7=BB?=
=?UTF-8?q?=204.X=20=E6=95=B0=E6=8D=AE=E5=BA=93=E5=8A=A0=E8=A7=A3=E5=AF=86?=
=?UTF-8?q?=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pom.xml | 8 ++
ruoyi-common/pom.xml | 1 +
ruoyi-common/ruoyi-common-bom/pom.xml | 7 ++
ruoyi-common/ruoyi-common-encrypt/pom.xml | 43 +++++++
.../encrypt/annotation/EncryptField.java | 44 +++++++
.../config/EncryptorAutoConfiguration.java | 39 ++++++
.../common/encrypt/core/EncryptContext.java | 41 +++++++
.../common/encrypt/core/EncryptorManager.java | 94 ++++++++++++++
.../ruoyi/common/encrypt/core/IEncryptor.java | 35 ++++++
.../core/encryptor/AbstractEncryptor.java | 18 +++
.../encrypt/core/encryptor/AesEncryptor.java | 69 +++++++++++
.../core/encryptor/Base64Encryptor.java | 48 ++++++++
.../encrypt/core/encryptor/RsaEncryptor.java | 65 ++++++++++
.../encrypt/core/encryptor/Sm2Encryptor.java | 64 ++++++++++
.../encrypt/core/encryptor/Sm4Encryptor.java | 67 ++++++++++
.../common/encrypt/enumd/AlgorithmType.java | 48 ++++++++
.../common/encrypt/enumd/EncodeType.java | 26 ++++
.../MybatisDecryptInterceptor.java | 108 ++++++++++++++++
.../MybatisEncryptInterceptor.java | 115 ++++++++++++++++++
.../properties/EncryptorProperties.java | 50 ++++++++
...ot.autoconfigure.AutoConfiguration.imports | 1 +
ruoyi-modules/ruoyi-demo/pom.xml | 5 +
.../controller/TestEncryptController.java | 55 +++++++++
.../ruoyi/demo/domain/TestDemoEncrypt.java | 29 +++++
.../demo/mapper/TestDemoEncryptMapper.java | 13 ++
25 files changed, 1093 insertions(+)
create mode 100644 ruoyi-common/ruoyi-common-encrypt/pom.xml
create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/annotation/EncryptField.java
create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/config/EncryptorAutoConfiguration.java
create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/EncryptContext.java
create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/EncryptorManager.java
create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/IEncryptor.java
create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/AbstractEncryptor.java
create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/AesEncryptor.java
create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/Base64Encryptor.java
create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/RsaEncryptor.java
create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/Sm2Encryptor.java
create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/Sm4Encryptor.java
create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/enumd/AlgorithmType.java
create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/enumd/EncodeType.java
create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/interceptor/MybatisDecryptInterceptor.java
create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/interceptor/MybatisEncryptInterceptor.java
create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/properties/EncryptorProperties.java
create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestEncryptController.java
create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/TestDemoEncrypt.java
create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestDemoEncryptMapper.java
diff --git a/pom.xml b/pom.xml
index 8af16697e..8f687cca4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -36,6 +36,7 @@
2.14.2
2.3.1
1.18.24
+ 1.72
1.33
@@ -286,6 +287,13 @@
${snakeyaml.version}
+
+
+ org.bouncycastle
+ bcprov-jdk15to18
+ ${bouncycastle.version}
+
+
com.ruoyi
ruoyi-system
diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml
index 469235813..af49f5ffb 100644
--- a/ruoyi-common/pom.xml
+++ b/ruoyi-common/pom.xml
@@ -30,6 +30,7 @@
ruoyi-common-translation
ruoyi-common-sensitive
ruoyi-common-json
+ ruoyi-common-encrypt
ruoyi-common
diff --git a/ruoyi-common/ruoyi-common-bom/pom.xml b/ruoyi-common/ruoyi-common-bom/pom.xml
index 739bfb6a9..72f28e462 100644
--- a/ruoyi-common/ruoyi-common-bom/pom.xml
+++ b/ruoyi-common/ruoyi-common-bom/pom.xml
@@ -145,6 +145,13 @@
${revision}
+
+
+ com.ruoyi
+ ruoyi-common-encrypt
+ ${revision}
+
+
diff --git a/ruoyi-common/ruoyi-common-encrypt/pom.xml b/ruoyi-common/ruoyi-common-encrypt/pom.xml
new file mode 100644
index 000000000..22aca400c
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-encrypt/pom.xml
@@ -0,0 +1,43 @@
+
+
+
+ com.ruoyi
+ ruoyi-common
+ ${revision}
+ ../pom.xml
+
+ 4.0.0
+
+ ruoyi-common-encrypt
+
+
+ ruoyi-common-encrypt 数据加解密模块
+
+
+
+
+
+ com.ruoyi
+ ruoyi-common-core
+
+
+
+ org.mybatis.spring.boot
+ mybatis-spring-boot-starter
+
+
+
+ org.bouncycastle
+ bcprov-jdk15to18
+
+
+
+ cn.hutool
+ hutool-crypto
+
+
+
+
+
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/annotation/EncryptField.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/annotation/EncryptField.java
new file mode 100644
index 000000000..f549a6a8e
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/annotation/EncryptField.java
@@ -0,0 +1,44 @@
+package com.ruoyi.common.encrypt.annotation;
+
+import com.ruoyi.common.encrypt.enumd.AlgorithmType;
+import com.ruoyi.common.encrypt.enumd.EncodeType;
+
+import java.lang.annotation.*;
+
+/**
+ * 字段加密注解
+ *
+ * @author 老马
+ */
+@Documented
+@Inherited
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface EncryptField {
+
+ /**
+ * 加密算法
+ */
+ AlgorithmType algorithm() default AlgorithmType.DEFAULT;
+
+ /**
+ * 秘钥。AES、SM4需要
+ */
+ String password() default "";
+
+ /**
+ * 公钥。RSA、SM2需要
+ */
+ String publicKey() default "";
+
+ /**
+ * 公钥。RSA、SM2需要
+ */
+ String privateKey() default "";
+
+ /**
+ * 编码方式。对加密算法为BASE64的不起作用
+ */
+ EncodeType encode() default EncodeType.DEFAULT;
+
+}
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/config/EncryptorAutoConfiguration.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/config/EncryptorAutoConfiguration.java
new file mode 100644
index 000000000..d77226d0a
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/config/EncryptorAutoConfiguration.java
@@ -0,0 +1,39 @@
+package com.ruoyi.common.encrypt.config;
+
+import com.ruoyi.common.encrypt.core.EncryptorManager;
+import com.ruoyi.common.encrypt.interceptor.MybatisDecryptInterceptor;
+import com.ruoyi.common.encrypt.interceptor.MybatisEncryptInterceptor;
+import com.ruoyi.common.encrypt.properties.EncryptorProperties;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+
+/**
+ * 加解密配置
+ *
+ * @author 老马
+ * @version 4.6.0
+ */
+@AutoConfiguration
+@ConditionalOnProperty(value = "mybatis-encryptor.enable", havingValue = "true")
+public class EncryptorAutoConfiguration {
+
+ @Autowired
+ private EncryptorProperties properties;
+
+ @Bean
+ public EncryptorManager encryptorManager() {
+ return new EncryptorManager();
+ }
+
+ @Bean
+ public MybatisEncryptInterceptor mybatisEncryptInterceptor(EncryptorManager encryptorManager) {
+ return new MybatisEncryptInterceptor(encryptorManager, properties);
+ }
+
+ @Bean
+ public MybatisDecryptInterceptor mybatisDecryptInterceptor(EncryptorManager encryptorManager) {
+ return new MybatisDecryptInterceptor(encryptorManager, properties);
+ }
+}
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/EncryptContext.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/EncryptContext.java
new file mode 100644
index 000000000..ff3825488
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/EncryptContext.java
@@ -0,0 +1,41 @@
+package com.ruoyi.common.encrypt.core;
+
+import com.ruoyi.common.encrypt.enumd.AlgorithmType;
+import com.ruoyi.common.encrypt.enumd.EncodeType;
+import lombok.Data;
+
+/**
+ * 加密上下文 用于encryptor传递必要的参数。
+ *
+ * @author 老马
+ * @version 4.6.0
+ */
+@Data
+public class EncryptContext {
+
+ /**
+ * 默认算法
+ */
+ private AlgorithmType algorithm;
+
+ /**
+ * 安全秘钥
+ */
+ private String password;
+
+ /**
+ * 公钥
+ */
+ private String publicKey;
+
+ /**
+ * 私钥
+ */
+ private String privateKey;
+
+ /**
+ * 编码方式,base64/hex
+ */
+ private EncodeType encode;
+
+}
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/EncryptorManager.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/EncryptorManager.java
new file mode 100644
index 000000000..d86eb71ad
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/EncryptorManager.java
@@ -0,0 +1,94 @@
+package com.ruoyi.common.encrypt.core;
+
+import cn.hutool.core.util.ReflectUtil;
+import com.ruoyi.common.encrypt.annotation.EncryptField;
+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 encryptorMap = new ConcurrentHashMap<>();
+
+ /**
+ * 类加密字段缓存
+ */
+ Map, Set> fieldCache = new ConcurrentHashMap<>();
+
+ /**
+ * 获取类加密字段缓存
+ */
+ public Set getFieldCache(Class> sourceClazz) {
+ return fieldCache.computeIfAbsent(sourceClazz, clazz -> {
+ Field[] declaredFields = clazz.getDeclaredFields();
+ Set 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);
+ }
+
+}
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/IEncryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/IEncryptor.java
new file mode 100644
index 000000000..d9642c0d1
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/IEncryptor.java
@@ -0,0 +1,35 @@
+package com.ruoyi.common.encrypt.core;
+
+import com.ruoyi.common.encrypt.enumd.AlgorithmType;
+import com.ruoyi.common.encrypt.enumd.EncodeType;
+
+/**
+ * 加解者
+ *
+ * @author 老马
+ * @version 4.6.0
+ */
+public interface IEncryptor {
+
+ /**
+ * 获得当前算法
+ */
+ AlgorithmType algorithm();
+
+ /**
+ * 加密
+ *
+ * @param value 待加密字符串
+ * @param encodeType 加密后的编码格式
+ * @return 加密后的字符串
+ */
+ String encrypt(String value, EncodeType encodeType);
+
+ /**
+ * 解密
+ *
+ * @param value 待加密字符串
+ * @return 解密后的字符串
+ */
+ String decrypt(String value);
+}
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/AbstractEncryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/AbstractEncryptor.java
new file mode 100644
index 000000000..b068ce77a
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/AbstractEncryptor.java
@@ -0,0 +1,18 @@
+package com.ruoyi.common.encrypt.core.encryptor;
+
+import com.ruoyi.common.encrypt.core.EncryptContext;
+import com.ruoyi.common.encrypt.core.IEncryptor;
+
+/**
+ * 所有加密执行者的基类
+ *
+ * @author 老马
+ * @version 4.6.0
+ */
+public abstract class AbstractEncryptor implements IEncryptor {
+
+ public AbstractEncryptor(EncryptContext context) {
+ // 用户配置校验与配置注入
+ }
+
+}
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/AesEncryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/AesEncryptor.java
new file mode 100644
index 000000000..ea89d2cb7
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/AesEncryptor.java
@@ -0,0 +1,69 @@
+package com.ruoyi.common.encrypt.core.encryptor;
+
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.crypto.SecureUtil;
+import cn.hutool.crypto.symmetric.AES;
+import com.ruoyi.common.encrypt.core.EncryptContext;
+import com.ruoyi.common.encrypt.enumd.AlgorithmType;
+import com.ruoyi.common.encrypt.enumd.EncodeType;
+
+import java.nio.charset.StandardCharsets;
+
+/**
+ * AES算法实现
+ *
+ * @author 老马
+ * @version 4.6.0
+ */
+public class AesEncryptor extends AbstractEncryptor {
+
+ private final AES aes;
+
+ public AesEncryptor(EncryptContext context) {
+ super(context);
+ String password = context.getPassword();
+ if (StrUtil.isBlank(password)) {
+ throw new IllegalArgumentException("AES没有获得秘钥信息");
+ }
+ // aes算法的秘钥要求是16位、24位、32位
+ int[] array = {16, 24, 32};
+ if (!ArrayUtil.contains(array, password.length())) {
+ throw new IllegalArgumentException("AES秘钥长度应该为16位、24位、32位,实际为" + password.length() + "位");
+ }
+ aes = SecureUtil.aes(context.getPassword().getBytes(StandardCharsets.UTF_8));
+ }
+
+ /**
+ * 获得当前算法
+ */
+ @Override
+ public AlgorithmType algorithm() {
+ return AlgorithmType.AES;
+ }
+
+ /**
+ * 加密
+ *
+ * @param value 待加密字符串
+ * @param encodeType 加密后的编码格式
+ */
+ @Override
+ public String encrypt(String value, EncodeType encodeType) {
+ if (encodeType == EncodeType.HEX) {
+ return aes.encryptHex(value);
+ } else {
+ return aes.encryptBase64(value);
+ }
+ }
+
+ /**
+ * 解密
+ *
+ * @param value 待加密字符串
+ */
+ @Override
+ public String decrypt(String value) {
+ return this.aes.decryptStr(value);
+ }
+}
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/Base64Encryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/Base64Encryptor.java
new file mode 100644
index 000000000..70f3e0026
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/Base64Encryptor.java
@@ -0,0 +1,48 @@
+package com.ruoyi.common.encrypt.core.encryptor;
+
+import cn.hutool.core.codec.Base64;
+import com.ruoyi.common.encrypt.core.EncryptContext;
+import com.ruoyi.common.encrypt.enumd.AlgorithmType;
+import com.ruoyi.common.encrypt.enumd.EncodeType;
+
+/**
+ * Base64算法实现
+ *
+ * @author 老马
+ * @version 4.6.0
+ */
+public class Base64Encryptor extends AbstractEncryptor {
+
+ public Base64Encryptor(EncryptContext context) {
+ super(context);
+ }
+
+ /**
+ * 获得当前算法
+ */
+ @Override
+ public AlgorithmType algorithm() {
+ return AlgorithmType.BASE64;
+ }
+
+ /**
+ * 加密
+ *
+ * @param value 待加密字符串
+ * @param encodeType 加密后的编码格式
+ */
+ @Override
+ public String encrypt(String value, EncodeType encodeType) {
+ return Base64.encode(value);
+ }
+
+ /**
+ * 解密
+ *
+ * @param value 待加密字符串
+ */
+ @Override
+ public String decrypt(String value) {
+ return Base64.decodeStr(value);
+ }
+}
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/RsaEncryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/RsaEncryptor.java
new file mode 100644
index 000000000..bd7774ec2
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/RsaEncryptor.java
@@ -0,0 +1,65 @@
+package com.ruoyi.common.encrypt.core.encryptor;
+
+import cn.hutool.core.codec.Base64;
+import cn.hutool.crypto.SecureUtil;
+import cn.hutool.crypto.asymmetric.KeyType;
+import cn.hutool.crypto.asymmetric.RSA;
+import com.ruoyi.common.core.utils.StringUtils;
+import com.ruoyi.common.encrypt.core.EncryptContext;
+import com.ruoyi.common.encrypt.enumd.AlgorithmType;
+import com.ruoyi.common.encrypt.enumd.EncodeType;
+
+
+/**
+ * RSA算法实现
+ *
+ * @author 老马
+ * @version 4.6.0
+ */
+public class RsaEncryptor extends AbstractEncryptor {
+
+ private final RSA rsa;
+
+ public RsaEncryptor(EncryptContext context) {
+ super(context);
+ String privateKey = context.getPrivateKey();
+ String publicKey = context.getPublicKey();
+ if (StringUtils.isAnyEmpty(privateKey, publicKey)) {
+ throw new IllegalArgumentException("RSA公私钥均需要提供,公钥加密,私钥解密。");
+ }
+ this.rsa = SecureUtil.rsa(Base64.decode(privateKey), Base64.decode(publicKey));
+ }
+
+ /**
+ * 获得当前算法
+ */
+ @Override
+ public AlgorithmType algorithm() {
+ return AlgorithmType.RSA;
+ }
+
+ /**
+ * 加密
+ *
+ * @param value 待加密字符串
+ * @param encodeType 加密后的编码格式
+ */
+ @Override
+ public String encrypt(String value, EncodeType encodeType) {
+ if (encodeType == EncodeType.HEX) {
+ return rsa.encryptHex(value, KeyType.PublicKey);
+ } else {
+ return rsa.encryptBase64(value, KeyType.PublicKey);
+ }
+ }
+
+ /**
+ * 解密
+ *
+ * @param value 待加密字符串
+ */
+ @Override
+ public String decrypt(String value) {
+ return this.rsa.decryptStr(value, KeyType.PrivateKey);
+ }
+}
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/Sm2Encryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/Sm2Encryptor.java
new file mode 100644
index 000000000..1e0bb9f17
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/Sm2Encryptor.java
@@ -0,0 +1,64 @@
+package com.ruoyi.common.encrypt.core.encryptor;
+
+import cn.hutool.core.codec.Base64;
+import cn.hutool.crypto.SmUtil;
+import cn.hutool.crypto.asymmetric.KeyType;
+import cn.hutool.crypto.asymmetric.SM2;
+import com.ruoyi.common.core.utils.StringUtils;
+import com.ruoyi.common.encrypt.core.EncryptContext;
+import com.ruoyi.common.encrypt.enumd.AlgorithmType;
+import com.ruoyi.common.encrypt.enumd.EncodeType;
+
+/**
+ * sm2算法实现
+ *
+ * @author 老马
+ * @version 4.6.0
+ */
+public class Sm2Encryptor extends AbstractEncryptor {
+
+ private final SM2 sm2;
+
+ public Sm2Encryptor(EncryptContext context) {
+ super(context);
+ String privateKey = context.getPrivateKey();
+ String publicKey = context.getPublicKey();
+ if (StringUtils.isAnyEmpty(privateKey, publicKey)) {
+ throw new IllegalArgumentException("SM2公私钥均需要提供,公钥加密,私钥解密。");
+ }
+ this.sm2 = SmUtil.sm2(Base64.decode(privateKey), Base64.decode(publicKey));
+ }
+
+ /**
+ * 获得当前算法
+ */
+ @Override
+ public AlgorithmType algorithm() {
+ return AlgorithmType.SM2;
+ }
+
+ /**
+ * 加密
+ *
+ * @param value 待加密字符串
+ * @param encodeType 加密后的编码格式
+ */
+ @Override
+ public String encrypt(String value, EncodeType encodeType) {
+ if (encodeType == EncodeType.HEX) {
+ return sm2.encryptHex(value, KeyType.PublicKey);
+ } else {
+ return sm2.encryptBase64(value, KeyType.PublicKey);
+ }
+ }
+
+ /**
+ * 解密
+ *
+ * @param value 待加密字符串
+ */
+ @Override
+ public String decrypt(String value) {
+ return this.sm2.decryptStr(value, KeyType.PrivateKey);
+ }
+}
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/Sm4Encryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/Sm4Encryptor.java
new file mode 100644
index 000000000..b15050388
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/core/encryptor/Sm4Encryptor.java
@@ -0,0 +1,67 @@
+package com.ruoyi.common.encrypt.core.encryptor;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.crypto.SmUtil;
+import cn.hutool.crypto.symmetric.SM4;
+import com.ruoyi.common.encrypt.core.EncryptContext;
+import com.ruoyi.common.encrypt.enumd.AlgorithmType;
+import com.ruoyi.common.encrypt.enumd.EncodeType;
+
+import java.nio.charset.StandardCharsets;
+
+/**
+ * sm4算法实现
+ *
+ * @author 老马
+ * @version 4.6.0
+ */
+public class Sm4Encryptor extends AbstractEncryptor {
+
+ private final SM4 sm4;
+
+ public Sm4Encryptor(EncryptContext context) {
+ super(context);
+ String password = context.getPassword();
+ if (StrUtil.isBlank(password)) {
+ throw new IllegalArgumentException("SM4没有获得秘钥信息");
+ }
+ // sm4算法的秘钥要求是16位长度
+ if (16 != password.length()) {
+ throw new IllegalArgumentException("SM4秘钥长度应该为16位,实际为" + password.length() + "位");
+ }
+ this.sm4 = SmUtil.sm4(password.getBytes(StandardCharsets.UTF_8));
+ }
+
+ /**
+ * 获得当前算法
+ */
+ @Override
+ public AlgorithmType algorithm() {
+ return AlgorithmType.SM4;
+ }
+
+ /**
+ * 加密
+ *
+ * @param value 待加密字符串
+ * @param encodeType 加密后的编码格式
+ */
+ @Override
+ public String encrypt(String value, EncodeType encodeType) {
+ if (encodeType == EncodeType.HEX) {
+ return sm4.encryptHex(value);
+ } else {
+ return sm4.encryptBase64(value);
+ }
+ }
+
+ /**
+ * 解密
+ *
+ * @param value 待加密字符串
+ */
+ @Override
+ public String decrypt(String value) {
+ return this.sm4.decryptStr(value);
+ }
+}
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/enumd/AlgorithmType.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/enumd/AlgorithmType.java
new file mode 100644
index 000000000..ff02ecb75
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/enumd/AlgorithmType.java
@@ -0,0 +1,48 @@
+package com.ruoyi.common.encrypt.enumd;
+
+import com.ruoyi.common.encrypt.core.encryptor.*;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 算法名称
+ *
+ * @author 老马
+ * @version 4.6.0
+ */
+@Getter
+@AllArgsConstructor
+public enum AlgorithmType {
+
+ /**
+ * 默认走yml配置
+ */
+ DEFAULT(null),
+
+ /**
+ * base64
+ */
+ BASE64(Base64Encryptor.class),
+
+ /**
+ * aes
+ */
+ AES(AesEncryptor.class),
+
+ /**
+ * rsa
+ */
+ RSA(RsaEncryptor.class),
+
+ /**
+ * sm2
+ */
+ SM2(Sm2Encryptor.class),
+
+ /**
+ * sm4
+ */
+ SM4(Sm4Encryptor.class);
+
+ private final Class extends AbstractEncryptor> clazz;
+}
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/enumd/EncodeType.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/enumd/EncodeType.java
new file mode 100644
index 000000000..f8d54999a
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/enumd/EncodeType.java
@@ -0,0 +1,26 @@
+package com.ruoyi.common.encrypt.enumd;
+
+/**
+ * 编码类型
+ *
+ * @author 老马
+ * @version 4.6.0
+ */
+public enum EncodeType {
+
+ /**
+ * 默认使用yml配置
+ */
+ DEFAULT,
+
+ /**
+ * base64编码
+ */
+ BASE64,
+
+ /**
+ * 16进制编码
+ */
+ HEX;
+
+}
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/interceptor/MybatisDecryptInterceptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/interceptor/MybatisDecryptInterceptor.java
new file mode 100644
index 000000000..925d4e419
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/interceptor/MybatisDecryptInterceptor.java
@@ -0,0 +1,108 @@
+package com.ruoyi.common.encrypt.interceptor;
+
+import cn.hutool.core.collection.CollectionUtil;
+import com.ruoyi.common.core.utils.StringUtils;
+import com.ruoyi.common.encrypt.annotation.EncryptField;
+import com.ruoyi.common.encrypt.core.EncryptContext;
+import com.ruoyi.common.encrypt.core.EncryptorManager;
+import com.ruoyi.common.encrypt.enumd.AlgorithmType;
+import com.ruoyi.common.encrypt.enumd.EncodeType;
+import com.ruoyi.common.encrypt.properties.EncryptorProperties;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.ibatis.executor.resultset.ResultSetHandler;
+import org.apache.ibatis.plugin.*;
+
+import java.lang.reflect.Field;
+import java.sql.Statement;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+/**
+ * 出参解密拦截器
+ *
+ * @author 老马
+ * @version 4.6.0
+ */
+@Slf4j
+@Intercepts({@Signature(
+ type = ResultSetHandler.class,
+ method = "handleResultSets",
+ args = {Statement.class})
+})
+@AllArgsConstructor
+public class MybatisDecryptInterceptor implements Interceptor {
+
+ private final EncryptorManager encryptorManager;
+ private final EncryptorProperties defaultProperties;
+
+ @Override
+ public Object intercept(Invocation invocation) throws Throwable {
+ // 获取执行mysql执行结果
+ Object result = invocation.proceed();
+ if (result == null) {
+ return null;
+ }
+ decryptHandler(result);
+ return result;
+ }
+
+ /**
+ * 解密对象
+ *
+ * @param sourceObject 待加密对象
+ */
+ private void decryptHandler(Object sourceObject) {
+ if (sourceObject instanceof Map) {
+ ((Map, Object>) sourceObject).values().forEach(this::decryptHandler);
+ return;
+ }
+ if (sourceObject instanceof List) {
+ // 判断第一个元素是否含有注解。如果没有直接返回,提高效率
+ Object firstItem = ((List>) sourceObject).get(0);
+ if (CollectionUtil.isEmpty(encryptorManager.getFieldCache(firstItem.getClass()))) {
+ return;
+ }
+ ((List>) sourceObject).forEach(this::decryptHandler);
+ return;
+ }
+ Set fields = encryptorManager.getFieldCache(sourceObject.getClass());
+ try {
+ for (Field field : fields) {
+ field.set(sourceObject, this.decryptField(String.valueOf(field.get(sourceObject)), field));
+ }
+ } catch (Exception e) {
+ log.error("处理解密字段时出错", e);
+ }
+ }
+
+ /**
+ * 字段值进行加密。通过字段的批注注册新的加密算法
+ *
+ * @param value 待加密的值
+ * @param field 待加密字段
+ * @return 加密后结果
+ */
+ private String decryptField(String value, Field field) {
+ EncryptField encryptField = field.getAnnotation(EncryptField.class);
+ EncryptContext encryptContext = new EncryptContext();
+ encryptContext.setAlgorithm(encryptField.algorithm() == AlgorithmType.DEFAULT ? defaultProperties.getAlgorithm() : encryptField.algorithm());
+ encryptContext.setEncode(encryptField.encode() == EncodeType.DEFAULT ? defaultProperties.getEncode() : encryptField.encode());
+ encryptContext.setPassword(StringUtils.isBlank(encryptField.password()) ? defaultProperties.getPassword() : encryptField.password());
+ encryptContext.setPrivateKey(StringUtils.isBlank(encryptField.privateKey()) ? defaultProperties.getPrivateKey() : encryptField.privateKey());
+ encryptContext.setPublicKey(StringUtils.isBlank(encryptField.publicKey()) ? defaultProperties.getPublicKey() : encryptField.publicKey());
+ return this.encryptorManager.decrypt(value, encryptContext);
+ }
+
+ @Override
+ public Object plugin(Object target) {
+ return Plugin.wrap(target, this);
+ }
+
+ @Override
+ public void setProperties(Properties properties) {
+
+ }
+}
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/interceptor/MybatisEncryptInterceptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/interceptor/MybatisEncryptInterceptor.java
new file mode 100644
index 000000000..97fc0a450
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/interceptor/MybatisEncryptInterceptor.java
@@ -0,0 +1,115 @@
+package com.ruoyi.common.encrypt.interceptor;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.ruoyi.common.core.utils.StringUtils;
+import com.ruoyi.common.encrypt.annotation.EncryptField;
+import com.ruoyi.common.encrypt.core.EncryptContext;
+import com.ruoyi.common.encrypt.core.EncryptorManager;
+import com.ruoyi.common.encrypt.enumd.AlgorithmType;
+import com.ruoyi.common.encrypt.enumd.EncodeType;
+import com.ruoyi.common.encrypt.properties.EncryptorProperties;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.ibatis.executor.parameter.ParameterHandler;
+import org.apache.ibatis.plugin.Interceptor;
+import org.apache.ibatis.plugin.Intercepts;
+import org.apache.ibatis.plugin.Invocation;
+import org.apache.ibatis.plugin.Signature;
+
+import java.lang.reflect.Field;
+import java.sql.PreparedStatement;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+/**
+ * 入参加密拦截器
+ *
+ * @author 老马
+ * @version 4.6.0
+ */
+@Slf4j
+@Intercepts({@Signature(
+ type = ParameterHandler.class,
+ method = "setParameters",
+ args = {PreparedStatement.class})
+})
+@AllArgsConstructor
+public class MybatisEncryptInterceptor implements Interceptor {
+
+ private final EncryptorManager encryptorManager;
+ private final EncryptorProperties defaultProperties;
+
+ @Override
+ public Object intercept(Invocation invocation) throws Throwable {
+ return invocation;
+ }
+
+ @Override
+ public Object plugin(Object target) {
+ if (target instanceof ParameterHandler) {
+ // 进行加密操作
+ ParameterHandler parameterHandler = (ParameterHandler) target;
+ Object parameterObject = parameterHandler.getParameterObject();
+ if (ObjectUtil.isNotNull(parameterObject) && !(parameterObject instanceof String)) {
+ this.encryptHandler(parameterObject);
+ }
+ }
+ return target;
+ }
+
+ /**
+ * 加密对象
+ *
+ * @param sourceObject 待加密对象
+ */
+ @SuppressWarnings("unchecked cast")
+ private void encryptHandler(Object sourceObject) {
+ if (sourceObject instanceof Map) {
+ ((Map, Object>) sourceObject).values().forEach(this::encryptHandler);
+ return;
+ }
+ if (sourceObject instanceof List) {
+ // 判断第一个元素是否含有注解。如果没有直接返回,提高效率
+ Object firstItem = ((List>) sourceObject).get(0);
+ if (CollectionUtil.isEmpty(encryptorManager.getFieldCache(firstItem.getClass()))) {
+ return;
+ }
+ ((List>) sourceObject).forEach(this::encryptHandler);
+ return;
+ }
+ Set fields = encryptorManager.getFieldCache(sourceObject.getClass());
+ try {
+ for (Field field : fields) {
+ field.set(sourceObject, this.encryptField(String.valueOf(field.get(sourceObject)), field));
+ }
+ } catch (Exception e) {
+ log.error("处理加密字段时出错", e);
+ }
+ }
+
+ /**
+ * 字段值进行加密。通过字段的批注注册新的加密算法
+ *
+ * @param value 待加密的值
+ * @param field 待加密字段
+ * @return 加密后结果
+ */
+ private String encryptField(String value, Field field) {
+ EncryptField encryptField = field.getAnnotation(EncryptField.class);
+ EncryptContext encryptContext = new EncryptContext();
+ encryptContext.setAlgorithm(encryptField.algorithm() == AlgorithmType.DEFAULT ? defaultProperties.getAlgorithm() : encryptField.algorithm());
+ encryptContext.setEncode(encryptField.encode() == EncodeType.DEFAULT ? defaultProperties.getEncode() : encryptField.encode());
+ encryptContext.setPassword(StringUtils.isBlank(encryptField.password()) ? defaultProperties.getPassword() : encryptField.password());
+ encryptContext.setPrivateKey(StringUtils.isBlank(encryptField.privateKey()) ? defaultProperties.getPrivateKey() : encryptField.privateKey());
+ encryptContext.setPublicKey(StringUtils.isBlank(encryptField.publicKey()) ? defaultProperties.getPublicKey() : encryptField.publicKey());
+ return this.encryptorManager.encrypt(value, encryptContext);
+ }
+
+
+ @Override
+ public void setProperties(Properties properties) {
+ }
+}
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/properties/EncryptorProperties.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/properties/EncryptorProperties.java
new file mode 100644
index 000000000..bd8c28d0e
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/properties/EncryptorProperties.java
@@ -0,0 +1,50 @@
+package com.ruoyi.common.encrypt.properties;
+
+import com.ruoyi.common.encrypt.enumd.AlgorithmType;
+import com.ruoyi.common.encrypt.enumd.EncodeType;
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * 加解密属性配置类
+ *
+ * @author 老马
+ * @version 4.6.0
+ */
+@Data
+@Component
+@ConfigurationProperties(prefix = "mybatis-encryptor")
+public class EncryptorProperties {
+
+ /**
+ * 过滤开关
+ */
+ private Boolean enable;
+
+ /**
+ * 默认算法
+ */
+ private AlgorithmType algorithm;
+
+ /**
+ * 安全秘钥
+ */
+ private String password;
+
+ /**
+ * 公钥
+ */
+ private String publicKey;
+
+ /**
+ * 私钥
+ */
+ private String privateKey;
+
+ /**
+ * 编码方式,base64/hex
+ */
+ private EncodeType encode;
+
+}
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-encrypt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 000000000..e1063e2bc
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+com.ruoyi.common.encrypt.config.EncryptorAutoConfiguration
diff --git a/ruoyi-modules/ruoyi-demo/pom.xml b/ruoyi-modules/ruoyi-demo/pom.xml
index 7f8eac032..cd7bdb134 100644
--- a/ruoyi-modules/ruoyi-demo/pom.xml
+++ b/ruoyi-modules/ruoyi-demo/pom.xml
@@ -83,6 +83,11 @@
ruoyi-common-sensitive
+
+ com.ruoyi
+ ruoyi-common-encrypt
+
+
diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestEncryptController.java b/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestEncryptController.java
new file mode 100644
index 000000000..6abe4e184
--- /dev/null
+++ b/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/controller/TestEncryptController.java
@@ -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