diff --git a/ruoyi-common/ruoyi-common-encrypt/pom.xml b/ruoyi-common/ruoyi-common-encrypt/pom.xml index df3222bee..baa59319a 100644 --- a/ruoyi-common/ruoyi-common-encrypt/pom.xml +++ b/ruoyi-common/ruoyi-common-encrypt/pom.xml @@ -42,6 +42,17 @@ spring-webmvc + + com.baomidou + mybatis-plus-spring-boot3-starter + + + org.mybatis + mybatis-spring + + + + diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/EncryptorAutoConfiguration.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/EncryptorAutoConfiguration.java index e988a3a2c..a0e86a6a6 100644 --- a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/EncryptorAutoConfiguration.java +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/EncryptorAutoConfiguration.java @@ -1,5 +1,11 @@ package org.dromara.common.encrypt.config; +import cn.hutool.core.collection.CollectionUtil; +import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration; +import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.io.Resources; +import org.dromara.common.encrypt.annotation.EncryptField; import org.dromara.common.encrypt.core.EncryptorManager; import org.dromara.common.encrypt.interceptor.MybatisDecryptInterceptor; import org.dromara.common.encrypt.interceptor.MybatisEncryptInterceptor; @@ -8,7 +14,20 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.core.type.ClassMetadata; +import org.springframework.core.type.classreading.CachingMetadataReaderFactory; +import org.springframework.util.ClassUtils; + +import java.lang.reflect.Field; +import java.util.*; +import java.util.stream.Collectors; + +import static org.springframework.util.StringUtils.tokenizeToStringArray; /** * 加解密配置 @@ -16,17 +35,66 @@ import org.springframework.context.annotation.Bean; * @author 老马 * @version 4.6.0 */ -@AutoConfiguration +@AutoConfiguration(after = MybatisPlusAutoConfiguration.class) @EnableConfigurationProperties(EncryptorProperties.class) @ConditionalOnProperty(value = "mybatis-encryptor.enable", havingValue = "true") +@Slf4j public class EncryptorAutoConfiguration { @Autowired private EncryptorProperties properties; + @Autowired + private MybatisPlusProperties mybatisPlusProperties; @Bean public EncryptorManager encryptorManager() { - return new EncryptorManager(); + Map, Set> fieldCache = scanEncryptClasses(mybatisPlusProperties.getTypeAliasesPackage()); + return new EncryptorManager(fieldCache); + } + + // 通过typeAliasesPackage设置的扫描包,来确定哪些实体类进行缓存 + private Map, Set> scanEncryptClasses(String typeAliasesPackage) { + Map, Set> fieldCache = new HashMap<>(); + try { + String[] packagePatternArray = tokenizeToStringArray(typeAliasesPackage, + ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); + for (String packagePattern : packagePatternArray) { + Resource[] resources = new PathMatchingResourcePatternResolver().getResources(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + + ClassUtils.convertClassNameToResourcePath(packagePattern) + "/**/*.class"); + for (Resource resource : resources) { + ClassMetadata classMetadata = new CachingMetadataReaderFactory().getMetadataReader(resource).getClassMetadata(); + Class clazz = Resources.classForName(classMetadata.getClassName()); + Set encryptFieldSet = getEncryptFieldSetFromClazz(clazz); + if(CollectionUtil.isNotEmpty(encryptFieldSet)) { + fieldCache.put(clazz, encryptFieldSet); + } + } + } + }catch (Exception e) { + log.error("初始化数据安全缓存时出错:{}", e.getMessage()); + } + return fieldCache; + } + + // 获得一个类的加密字段集合 + private Set getEncryptFieldSetFromClazz(Class clazz) { + Set fieldSet = new HashSet<>(); + // 判断clazz如果是接口,内部类,匿名类就直接返回 + if (clazz.isInterface() || clazz.isMemberClass() || clazz.isAnonymousClass()) { + return fieldSet; + } + while (clazz != null) { + Field[] fields = clazz.getDeclaredFields(); + fieldSet.addAll(Arrays.asList(fields)); + clazz = clazz.getSuperclass(); + } + fieldSet = fieldSet.stream().filter(field -> + field.isAnnotationPresent(EncryptField.class) && field.getType() == String.class) + .collect(Collectors.toSet()); + for (Field field : fieldSet) { + field.setAccessible(true); + } + return fieldSet; } @Bean @@ -38,4 +106,8 @@ public class EncryptorAutoConfiguration { public MybatisDecryptInterceptor mybatisDecryptInterceptor(EncryptorManager encryptorManager) { return new MybatisDecryptInterceptor(encryptorManager, properties); } + } + + + diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptorManager.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptorManager.java index 498b4b85b..c2b9cae50 100644 --- a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptorManager.java +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptorManager.java @@ -1,16 +1,14 @@ package org.dromara.common.encrypt.core; +import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ReflectUtil; +import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.dromara.common.encrypt.annotation.EncryptField; import java.lang.reflect.Field; -import java.util.Arrays; -import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; /** * 加密管理类 @@ -19,6 +17,7 @@ import java.util.stream.Collectors; * @version 4.6.0 */ @Slf4j +@NoArgsConstructor public class EncryptorManager { /** @@ -31,25 +30,24 @@ public class EncryptorManager { */ Map, Set> fieldCache = new ConcurrentHashMap<>(); + /** + * 构造方法传入类加密字段缓存 + * + * @param fieldCache 类加密字段缓存 + */ + public EncryptorManager(Map, Set> fieldCache) { + this.fieldCache = fieldCache; + } + + /** * 获取类加密字段缓存 */ public Set getFieldCache(Class sourceClazz) { - return fieldCache.computeIfAbsent(sourceClazz, clazz -> { - Set fieldSet = new HashSet<>(); - while (clazz != null) { - Field[] fields = clazz.getDeclaredFields(); - fieldSet.addAll(Arrays.asList(fields)); - clazz = clazz.getSuperclass(); - } - fieldSet = fieldSet.stream().filter(field -> - field.isAnnotationPresent(EncryptField.class) && field.getType() == String.class) - .collect(Collectors.toSet()); - for (Field field : fieldSet) { - field.setAccessible(true); - } - return fieldSet; - }); + if(ObjectUtil.isNotNull(fieldCache)) { + return fieldCache.get(sourceClazz); + } + return null; } /** diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisDecryptInterceptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisDecryptInterceptor.java index 7c2508f86..460aa360e 100644 --- a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisDecryptInterceptor.java +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisDecryptInterceptor.java @@ -73,7 +73,11 @@ public class MybatisDecryptInterceptor implements Interceptor { list.forEach(this::decryptHandler); return; } + // 不在缓存中的类,就是没有加密注解的类(当然也有可能是typeAliasesPackage写错) Set fields = encryptorManager.getFieldCache(sourceObject.getClass()); + if(ObjectUtil.isNull(fields)){ + return; + } try { for (Field field : fields) { field.set(sourceObject, this.decryptField(Convert.toStr(field.get(sourceObject)), field)); diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java index 152f7db40..bcc2f4c9f 100644 --- a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java @@ -82,7 +82,11 @@ public class MybatisEncryptInterceptor implements Interceptor { list.forEach(this::encryptHandler); return; } + // 不在缓存中的类,就是没有加密注解的类(当然也有可能是typeAliasesPackage写错) Set fields = encryptorManager.getFieldCache(sourceObject.getClass()); + if(ObjectUtil.isNull(fields)){ + return; + } try { for (Field field : fields) { field.set(sourceObject, this.encryptField(Convert.toStr(field.get(sourceObject)), field));