add 新增 数据加解密模块 ruoyi-common-encrypt

This commit is contained in:
疯狂的狮子li
2023-02-05 14:41:54 +08:00
parent e039986248
commit 0711d75c66
22 changed files with 998 additions and 0 deletions

View File

@@ -230,6 +230,20 @@ mybatis-plus:
updateStrategy: NOT_NULL
where-strategy: NOT_NULL
# 数据加密
mybatis-encryptor:
# 是否开启加密
enable: false
# 默认加密算法
algorithm: BASE64
# 编码方式 BASE64/HEX。默认BASE64
encode: BASE64
# 安全秘钥 对称算法的秘钥 如AESSM4
password:
# 公私钥 非对称算法的公私钥 如SM2RSA
publicKey:
privateKey:
# swagger配置
swagger:
info:

View File

@@ -40,6 +40,7 @@
<easy-es.version>1.1.1</easy-es.version>
<elasticsearch.version>7.14.0</elasticsearch.version>
<skywalking-toolkit.version>8.13.0</skywalking-toolkit.version>
<bouncycastle.version>1.72</bouncycastle.version>
<!-- 临时修复 snakeyaml 漏洞 -->
<snakeyaml.version>1.33</snakeyaml.version>
@@ -268,6 +269,13 @@
<version>${xxl-job.version}</version>
</dependency>
<!-- 加密包引入 -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15to18</artifactId>
<version>${bouncycastle.version}</version>
</dependency>
<!-- logstash -->
<dependency>
<groupId>net.logstash.logback</groupId>

View File

@@ -35,6 +35,7 @@
<module>ruoyi-common-skylog</module>
<module>ruoyi-common-prometheus</module>
<module>ruoyi-common-translation</module>
<module>ruoyi-common-encrypt</module>
</modules>
<artifactId>ruoyi-common</artifactId>

View File

@@ -168,6 +168,12 @@
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common-encrypt</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
<version>1.5.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-common-encrypt</artifactId>
<description>
ruoyi-common-encrypt 数据加解密模块
</description>
<dependencies>
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common-core</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15to18</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-crypto</artifactId>
</dependency>
</dependencies>
</project>

View File

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

View File

@@ -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);
}
}

View File

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

View File

@@ -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<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);
}
}

View File

@@ -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);
}

View File

@@ -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) {
// 用户配置校验与配置注入
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

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

View File

@@ -0,0 +1,26 @@
package com.ruoyi.common.encrypt.enumd;
/**
* 编码类型
*
* @author 老马
* @version 4.6.0
*/
public enum EncodeType {
/**
* 默认使用yml配置
*/
DEFAULT,
/**
* base64编码
*/
BASE64,
/**
* 16进制编码
*/
HEX;
}

View File

@@ -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<Field> 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) {
}
}

View File

@@ -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<Field> 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) {
}
}

View File

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

View File

@@ -0,0 +1 @@
com.ruoyi.common.encrypt.config.EncryptorAutoConfiguration