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 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) 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) 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> test(String key, String value) { + if (!encryptEnable) { + throw new RuntimeException("加密功能未开启!"); + } + Map 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); + } + + +} diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/TestDemoEncrypt.java b/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/TestDemoEncrypt.java new file mode 100644 index 000000000..0214e8d58 --- /dev/null +++ b/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/domain/TestDemoEncrypt.java @@ -0,0 +1,29 @@ +package com.ruoyi.demo.domain; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.ruoyi.common.encrypt.annotation.EncryptField; +import com.ruoyi.common.encrypt.enumd.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; + +} diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestDemoEncryptMapper.java b/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestDemoEncryptMapper.java new file mode 100644 index 000000000..cef30afb1 --- /dev/null +++ b/ruoyi-modules/ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestDemoEncryptMapper.java @@ -0,0 +1,13 @@ +package com.ruoyi.demo.mapper; + +import com.ruoyi.common.mybatis.core.mapper.BaseMapperPlus; +import com.ruoyi.demo.domain.TestDemoEncrypt; + +/** + * 测试加密功能 + * + * @author Lion Li + */ +public interface TestDemoEncryptMapper extends BaseMapperPlus { + +}