mirror of
				https://github.com/dromara/RuoYi-Vue-Plus.git
				synced 2025-11-04 08:13:44 +08:00 
			
		
		
		
	add 新增 迁移 4.X 数据库加解密功能
This commit is contained in:
		
							
								
								
									
										8
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								pom.xml
									
									
									
									
									
								
							@@ -36,6 +36,7 @@
 | 
			
		||||
        <alibaba-ttl.version>2.14.2</alibaba-ttl.version>
 | 
			
		||||
        <xxl-job.version>2.3.1</xxl-job.version>
 | 
			
		||||
        <lombok.version>1.18.24</lombok.version>
 | 
			
		||||
        <bouncycastle.version>1.72</bouncycastle.version>
 | 
			
		||||
 | 
			
		||||
        <!-- 临时修复 snakeyaml 漏洞 -->
 | 
			
		||||
        <snakeyaml.version>1.33</snakeyaml.version>
 | 
			
		||||
@@ -286,6 +287,13 @@
 | 
			
		||||
                <version>${snakeyaml.version}</version>
 | 
			
		||||
            </dependency>
 | 
			
		||||
 | 
			
		||||
            <!-- 加密包引入 -->
 | 
			
		||||
            <dependency>
 | 
			
		||||
                <groupId>org.bouncycastle</groupId>
 | 
			
		||||
                <artifactId>bcprov-jdk15to18</artifactId>
 | 
			
		||||
                <version>${bouncycastle.version}</version>
 | 
			
		||||
            </dependency>
 | 
			
		||||
 | 
			
		||||
            <dependency>
 | 
			
		||||
                <groupId>com.ruoyi</groupId>
 | 
			
		||||
                <artifactId>ruoyi-system</artifactId>
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,7 @@
 | 
			
		||||
        <module>ruoyi-common-translation</module>
 | 
			
		||||
        <module>ruoyi-common-sensitive</module>
 | 
			
		||||
        <module>ruoyi-common-json</module>
 | 
			
		||||
        <module>ruoyi-common-encrypt</module>
 | 
			
		||||
    </modules>
 | 
			
		||||
 | 
			
		||||
    <artifactId>ruoyi-common</artifactId>
 | 
			
		||||
 
 | 
			
		||||
@@ -145,6 +145,13 @@
 | 
			
		||||
                <version>${revision}</version>
 | 
			
		||||
            </dependency>
 | 
			
		||||
 | 
			
		||||
            <!-- 数据库加解密模块 -->
 | 
			
		||||
            <dependency>
 | 
			
		||||
                <groupId>com.ruoyi</groupId>
 | 
			
		||||
                <artifactId>ruoyi-common-encrypt</artifactId>
 | 
			
		||||
                <version>${revision}</version>
 | 
			
		||||
            </dependency>
 | 
			
		||||
 | 
			
		||||
        </dependencies>
 | 
			
		||||
    </dependencyManagement>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										43
									
								
								ruoyi-common/ruoyi-common-encrypt/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								ruoyi-common/ruoyi-common-encrypt/pom.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
<?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>${revision}</version>
 | 
			
		||||
        <relativePath>../pom.xml</relativePath>
 | 
			
		||||
    </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.mybatis.spring.boot</groupId>
 | 
			
		||||
            <artifactId>mybatis-spring-boot-starter</artifactId>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.bouncycastle</groupId>
 | 
			
		||||
            <artifactId>bcprov-jdk15to18</artifactId>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>cn.hutool</groupId>
 | 
			
		||||
            <artifactId>hutool-crypto</artifactId>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
    </dependencies>
 | 
			
		||||
 | 
			
		||||
</project>
 | 
			
		||||
@@ -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;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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);
 | 
			
		||||
}
 | 
			
		||||
@@ -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) {
 | 
			
		||||
        // 用户配置校验与配置注入
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,26 @@
 | 
			
		||||
package com.ruoyi.common.encrypt.enumd;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 编码类型
 | 
			
		||||
 *
 | 
			
		||||
 * @author 老马
 | 
			
		||||
 * @version 4.6.0
 | 
			
		||||
 */
 | 
			
		||||
public enum EncodeType {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 默认使用yml配置
 | 
			
		||||
     */
 | 
			
		||||
    DEFAULT,
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * base64编码
 | 
			
		||||
     */
 | 
			
		||||
    BASE64,
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 16进制编码
 | 
			
		||||
     */
 | 
			
		||||
    HEX;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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) {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
com.ruoyi.common.encrypt.config.EncryptorAutoConfiguration
 | 
			
		||||
@@ -83,6 +83,11 @@
 | 
			
		||||
            <artifactId>ruoyi-common-sensitive</artifactId>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.ruoyi</groupId>
 | 
			
		||||
            <artifactId>ruoyi-common-encrypt</artifactId>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <!-- 短信 用哪个导入哪个依赖 -->
 | 
			
		||||
<!--        <dependency>-->
 | 
			
		||||
<!--            <groupId>com.aliyun</groupId>-->
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,55 @@
 | 
			
		||||
package com.ruoyi.demo.controller;
 | 
			
		||||
 | 
			
		||||
import com.ruoyi.common.core.domain.R;
 | 
			
		||||
import com.ruoyi.demo.domain.TestDemoEncrypt;
 | 
			
		||||
import com.ruoyi.demo.mapper.TestDemoEncryptMapper;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Value;
 | 
			
		||||
import org.springframework.validation.annotation.Validated;
 | 
			
		||||
import org.springframework.web.bind.annotation.GetMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.RequestMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.RestController;
 | 
			
		||||
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 测试数据库加解密功能
 | 
			
		||||
 *
 | 
			
		||||
 * @author Lion Li
 | 
			
		||||
 */
 | 
			
		||||
@Validated
 | 
			
		||||
@RestController
 | 
			
		||||
@RequestMapping("/demo/encrypt")
 | 
			
		||||
public class TestEncryptController {
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private TestDemoEncryptMapper mapper;
 | 
			
		||||
    @Value("${mybatis-encryptor.enable}")
 | 
			
		||||
    private Boolean encryptEnable;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 测试数据库加解密
 | 
			
		||||
     *
 | 
			
		||||
     * @param key   测试key
 | 
			
		||||
     * @param value 测试value
 | 
			
		||||
     */
 | 
			
		||||
    @GetMapping()
 | 
			
		||||
    public R<Map<String, TestDemoEncrypt>> test(String key, String value) {
 | 
			
		||||
        if (!encryptEnable) {
 | 
			
		||||
            throw new RuntimeException("加密功能未开启!");
 | 
			
		||||
        }
 | 
			
		||||
        Map<String, TestDemoEncrypt> map = new HashMap<>(2);
 | 
			
		||||
        TestDemoEncrypt demo = new TestDemoEncrypt();
 | 
			
		||||
        demo.setTestKey(key);
 | 
			
		||||
        demo.setValue(value);
 | 
			
		||||
        mapper.insert(demo);
 | 
			
		||||
        map.put("加密", demo);
 | 
			
		||||
        TestDemoEncrypt testDemo = mapper.selectById(demo.getId());
 | 
			
		||||
        map.put("解密", testDemo);
 | 
			
		||||
        return R.ok(map);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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<TestDemoEncryptMapper, TestDemoEncrypt, TestDemoEncrypt> {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user