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> ruoyi-common/pom.xml
@@ -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> ruoyi-common/ruoyi-common-bom/pom.xml
@@ -145,6 +145,13 @@ <version>${revision}</version> </dependency> <!-- æ°æ®åºå è§£å¯æ¨¡å --> <dependency> <groupId>com.ruoyi</groupId> <artifactId>ruoyi-common-encrypt</artifactId> <version>${revision}</version> </dependency> </dependencies> </dependencyManagement> ruoyi-common/ruoyi-common-encrypt/pom.xml
¶Ô±ÈÐÂÎļþ @@ -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> 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; } 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); } } 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; } 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<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); } } 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); } 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) { // ç¨æ·é ç½®æ ¡éªä¸é ç½®æ³¨å ¥ } } 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); } } 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); } } 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); } } 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); } } 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); } } ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/enumd/AlgorithmType.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,48 @@ package com.ruoyi.common.encrypt.enumd; import com.ruoyi.common.encrypt.core.encryptor.*; import lombok.AllArgsConstructor; import lombok.Getter; /** * ç®æ³åç§° * * @author è马 * @version 4.6.0 */ @Getter @AllArgsConstructor public enum AlgorithmType { /** * é»è®¤èµ°ymlé ç½® */ DEFAULT(null), /** * base64 */ BASE64(Base64Encryptor.class), /** * aes */ AES(AesEncryptor.class), /** * rsa */ RSA(RsaEncryptor.class), /** * sm2 */ SM2(Sm2Encryptor.class), /** * sm4 */ SM4(Sm4Encryptor.class); private final Class<? extends AbstractEncryptor> clazz; } 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; } ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/interceptor/MybatisDecryptInterceptor.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,108 @@ package com.ruoyi.common.encrypt.interceptor; import cn.hutool.core.collection.CollectionUtil; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.encrypt.annotation.EncryptField; import com.ruoyi.common.encrypt.core.EncryptContext; import com.ruoyi.common.encrypt.core.EncryptorManager; import com.ruoyi.common.encrypt.enumd.AlgorithmType; import com.ruoyi.common.encrypt.enumd.EncodeType; import com.ruoyi.common.encrypt.properties.EncryptorProperties; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.executor.resultset.ResultSetHandler; import org.apache.ibatis.plugin.*; import java.lang.reflect.Field; import java.sql.Statement; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; /** * åºåè§£å¯æ¦æªå¨ * * @author è马 * @version 4.6.0 */ @Slf4j @Intercepts({@Signature( type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class}) }) @AllArgsConstructor public class MybatisDecryptInterceptor implements Interceptor { private final EncryptorManager encryptorManager; private final EncryptorProperties defaultProperties; @Override public Object intercept(Invocation invocation) throws Throwable { // è·åæ§è¡mysqlæ§è¡ç»æ Object result = invocation.proceed(); if (result == null) { return null; } decryptHandler(result); return result; } /** * è§£å¯å¯¹è±¡ * * @param sourceObject å¾ å å¯å¯¹è±¡ */ private void decryptHandler(Object sourceObject) { if (sourceObject instanceof Map) { ((Map<?, Object>) sourceObject).values().forEach(this::decryptHandler); return; } if (sourceObject instanceof List) { // å¤æç¬¬ä¸ä¸ªå ç´ æ¯å¦å«ææ³¨è§£ãå¦ææ²¡æç´æ¥è¿åï¼æé«æç Object firstItem = ((List<?>) sourceObject).get(0); if (CollectionUtil.isEmpty(encryptorManager.getFieldCache(firstItem.getClass()))) { return; } ((List<?>) sourceObject).forEach(this::decryptHandler); return; } Set<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) { } } ruoyi-common/ruoyi-common-encrypt/src/main/java/com/ruoyi/common/encrypt/interceptor/MybatisEncryptInterceptor.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,115 @@ package com.ruoyi.common.encrypt.interceptor; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.ObjectUtil; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.encrypt.annotation.EncryptField; import com.ruoyi.common.encrypt.core.EncryptContext; import com.ruoyi.common.encrypt.core.EncryptorManager; import com.ruoyi.common.encrypt.enumd.AlgorithmType; import com.ruoyi.common.encrypt.enumd.EncodeType; import com.ruoyi.common.encrypt.properties.EncryptorProperties; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.executor.parameter.ParameterHandler; import org.apache.ibatis.plugin.Interceptor; import org.apache.ibatis.plugin.Intercepts; import org.apache.ibatis.plugin.Invocation; import org.apache.ibatis.plugin.Signature; import java.lang.reflect.Field; import java.sql.PreparedStatement; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; /** * å ¥åå 坿¦æªå¨ * * @author è马 * @version 4.6.0 */ @Slf4j @Intercepts({@Signature( type = ParameterHandler.class, method = "setParameters", args = {PreparedStatement.class}) }) @AllArgsConstructor public class MybatisEncryptInterceptor implements Interceptor { private final EncryptorManager encryptorManager; private final EncryptorProperties defaultProperties; @Override public Object intercept(Invocation invocation) throws Throwable { return invocation; } @Override public Object plugin(Object target) { if (target instanceof ParameterHandler) { // è¿è¡å å¯æä½ ParameterHandler parameterHandler = (ParameterHandler) target; Object parameterObject = parameterHandler.getParameterObject(); if (ObjectUtil.isNotNull(parameterObject) && !(parameterObject instanceof String)) { this.encryptHandler(parameterObject); } } return target; } /** * å å¯å¯¹è±¡ * * @param sourceObject å¾ å å¯å¯¹è±¡ */ @SuppressWarnings("unchecked cast") private void encryptHandler(Object sourceObject) { if (sourceObject instanceof Map) { ((Map<?, Object>) sourceObject).values().forEach(this::encryptHandler); return; } if (sourceObject instanceof List) { // å¤æç¬¬ä¸ä¸ªå ç´ æ¯å¦å«ææ³¨è§£ãå¦ææ²¡æç´æ¥è¿åï¼æé«æç Object firstItem = ((List<?>) sourceObject).get(0); if (CollectionUtil.isEmpty(encryptorManager.getFieldCache(firstItem.getClass()))) { return; } ((List<?>) sourceObject).forEach(this::encryptHandler); return; } Set<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) { } } 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; } 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 ruoyi-modules/ruoyi-demo/pom.xml
@@ -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>--> 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<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); } } 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; } 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<TestDemoEncryptMapper, TestDemoEncrypt, TestDemoEncrypt> { }