ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/EncryptorAutoConfiguration.java
@@ -1,11 +1,8 @@ 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; @@ -14,20 +11,7 @@ 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; /** * 加解密配置 @@ -43,58 +27,10 @@ @Autowired private EncryptorProperties properties; @Autowired private MybatisPlusProperties mybatisPlusProperties; @Bean public EncryptorManager encryptorManager() { Map<Class<?>, Set<Field>> fieldCache = scanEncryptClasses(mybatisPlusProperties.getTypeAliasesPackage()); return new EncryptorManager(fieldCache); } // 通过typeAliasesPackage设置的扫描包,来确定哪些实体类进行缓存 private Map<Class<?>, Set<Field>> scanEncryptClasses(String typeAliasesPackage) { Map<Class<?>, Set<Field>> 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<Field> encryptFieldSet = getEncryptFieldSetFromClazz(clazz); if(CollectionUtil.isNotEmpty(encryptFieldSet)) { fieldCache.put(clazz, encryptFieldSet); } } } }catch (Exception e) { log.error("初始化数据安全缓存时出错:{}", e.getMessage()); } return fieldCache; } // 获得一个类的加密字段集合 private Set<Field> getEncryptFieldSetFromClazz(Class<?> clazz) { Set<Field> 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; public EncryptorManager encryptorManager(MybatisPlusProperties mybatisPlusProperties) { return new EncryptorManager(mybatisPlusProperties.getTypeAliasesPackage()); } @Bean ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptorManager.java
@@ -1,14 +1,25 @@ package org.dromara.common.encrypt.core; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ReflectUtil; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.io.Resources; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.encrypt.annotation.EncryptField; import org.springframework.context.ConfigurableApplicationContext; 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.Map; import java.util.Set; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; /** * 加密管理类 @@ -33,10 +44,10 @@ /** * 构造方法传入类加密字段缓存 * * @param fieldCache 类加密字段缓存 * @param typeAliasesPackage 实体类包 */ public EncryptorManager(Map<Class<?>, Set<Field>> fieldCache) { this.fieldCache = fieldCache; public EncryptorManager(String typeAliasesPackage) { this.fieldCache = scanEncryptClasses(typeAliasesPackage); } @@ -44,7 +55,7 @@ * 获取类加密字段缓存 */ public Set<Field> getFieldCache(Class<?> sourceClazz) { if(ObjectUtil.isNotNull(fieldCache)) { if (ObjectUtil.isNotNull(fieldCache)) { return fieldCache.get(sourceClazz); } return null; @@ -95,4 +106,55 @@ return encryptor.decrypt(value); } /** * 通过 typeAliasesPackage 设置的扫描包 扫描缓存实体 */ private Map<Class<?>, Set<Field>> scanEncryptClasses(String typeAliasesPackage) { Map<Class<?>, Set<Field>> fieldCache = new HashMap<>(); PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory(); String[] packagePatternArray = StringUtils.splitPreserveAllTokens(typeAliasesPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); String classpath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX; try { for (String packagePattern : packagePatternArray) { String path = ClassUtils.convertClassNameToResourcePath(packagePattern); Resource[] resources = resolver.getResources(classpath + path + "/*.class"); for (Resource resource : resources) { ClassMetadata classMetadata = factory.getMetadataReader(resource).getClassMetadata(); Class<?> clazz = Resources.classForName(classMetadata.getClassName()); Set<Field> encryptFieldSet = getEncryptFieldSetFromClazz(clazz); if (CollUtil.isNotEmpty(encryptFieldSet)) { fieldCache.put(clazz, encryptFieldSet); } } } } catch (Exception e) { log.error("初始化数据安全缓存时出错:{}", e.getMessage()); } return fieldCache; } /** * 获得一个类的加密字段集合 */ private Set<Field> getEncryptFieldSetFromClazz(Class<?> clazz) { Set<Field> 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; } }