Skip to content

Commit

Permalink
fix: 重构并修复更新场景加密失效的问题(仍需处理 MP 和单参查询加密问题)
Browse files Browse the repository at this point in the history
  • Loading branch information
Charles7c committed Sep 5, 2024
1 parent 427143d commit e9b81f9
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 276 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,11 @@ public class StringConstants {
*/
public static final String ROUND_BRACKET_END = ")";

/**
* 等号(=)
*/
public static final String EQUALS = "=";

/**
* 路径模式
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.baomidou.mybatisplus.extension.plugins.handler.DataPermissionHandler;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import jakarta.annotation.PostConstruct;
import org.mybatis.spring.annotation.MapperScan;
Expand All @@ -43,6 +44,8 @@
import top.continew.starter.data.mp.datapermission.DataPermissionHandlerImpl;
import top.continew.starter.data.mp.handler.MybatisBaseEnumTypeHandler;

import java.util.Map;

/**
* MyBatis Plus 自动配置
*
Expand Down Expand Up @@ -76,6 +79,11 @@ public MybatisPlusPropertiesCustomizer mybatisPlusPropertiesCustomizer() {
@ConditionalOnMissingBean
public MybatisPlusInterceptor mybatisPlusInterceptor(MyBatisPlusExtensionProperties properties) {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 其他拦截器
Map<String, InnerInterceptor> innerInterceptors = SpringUtil.getBeansOfType(InnerInterceptor.class);
if (!innerInterceptors.isEmpty()) {
innerInterceptors.values().forEach(interceptor::addInnerInterceptor);
}
// 数据权限插件
MyBatisPlusExtensionProperties.DataPermissionProperties dataPermissionProperties = properties
.getDataPermission();
Expand Down
5 changes: 5 additions & 0 deletions continew-starter-dependencies/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,11 @@
<artifactId>mybatis-plus-core</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-extension</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>

<!-- MyBatis Flex(MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,简化开发、提高效率) -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<!-- MyBatis Plus(MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,简化开发、提高效率) -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-core</artifactId>
<artifactId>mybatis-plus-extension</artifactId>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public CryptoAutoConfiguration(CryptoProperties properties) {
* MyBatis 加密拦截器配置
*/
@Bean
@ConditionalOnMissingBean(MyBatisEncryptInterceptor.class)
@ConditionalOnMissingBean
public MyBatisEncryptInterceptor myBatisEncryptInterceptor() {
return new MyBatisEncryptInterceptor(properties);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,37 +16,22 @@

package top.continew.starter.security.crypto.core;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import top.continew.starter.core.constant.StringConstants;
import top.continew.starter.core.exception.BusinessException;
import top.continew.starter.security.crypto.annotation.FieldEncrypt;
import top.continew.starter.security.crypto.encryptor.IEncryptor;
import top.continew.starter.security.crypto.enums.Algorithm;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;

/**
* 字段解密拦截器
*
* @author Charles7c
* @since 1.4.0
*/
public abstract class AbstractMyBatisInterceptor implements Interceptor {

private static final Map<String, Map<String, FieldEncrypt>> ENCRYPT_PARAM_CACHE = new ConcurrentHashMap<>();
public abstract class AbstractMyBatisInterceptor {

/**
* 获取所有字符串类型、需要加/解密的、有值字段
Expand All @@ -58,10 +43,19 @@ public List<Field> getEncryptFields(Object obj) {
if (null == obj) {
return Collections.emptyList();
}
return Arrays.stream(ReflectUtil.getFields(obj.getClass()))
return this.getEncryptFields(obj.getClass());
}

/**
* 获取所有字符串类型、需要加/解密的、有值字段
*
* @param clazz 类型对象
* @return 字段列表
*/
public List<Field> getEncryptFields(Class<?> clazz) {
return Arrays.stream(ReflectUtil.getFields(clazz))
.filter(field -> String.class.equals(field.getType()))
.filter(field -> null != field.getAnnotation(FieldEncrypt.class))
.filter(field -> null != ReflectUtil.getFieldValue(obj, field))
.toList();
}

Expand All @@ -81,115 +75,4 @@ public IEncryptor getEncryptor(FieldEncrypt fieldEncrypt) {
// 使用自定义加/解密处理器
return SpringUtil.getBean(encryptorClass);
}

/**
* 获取加密参数
*
* @param mappedStatement 映射语句
* @return 加密参数
*/
public Map<String, FieldEncrypt> getEncryptParams(MappedStatement mappedStatement) {
return getEncryptParams(mappedStatement, null);
}

/**
* 获取加密参数
*
* @param mappedStatement 映射语句
* @param parameterCount 参数数量
* @return 加密参数
*/
public Map<String, FieldEncrypt> getEncryptParams(MappedStatement mappedStatement, Integer parameterCount) {
String mappedStatementId = mappedStatement.getId();
SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
if (SqlCommandType.UPDATE != sqlCommandType) {
return ENCRYPT_PARAM_CACHE.computeIfAbsent(mappedStatementId, key -> this
.getEncryptParams(mappedStatementId, parameterCount));
} else {
return this.getEncryptParams(mappedStatementId, parameterCount);
}
}

/**
* 获取参数名称
*
* @param parameter 参数
* @return 参数名称
*/
public String getParameterName(Parameter parameter) {
Param param = parameter.getAnnotation(Param.class);
return null != param ? param.value() : parameter.getName();
}

/**
* 获取加密参数列表
*
* @param mappedStatementId 映射语句 ID
* @param parameterCount 参数数量
* @return 加密参数列表
*/
private Map<String, FieldEncrypt> getEncryptParams(String mappedStatementId, Integer parameterCount) {
Method method = this.getMethod(mappedStatementId, parameterCount);
if (method == null) {
return Collections.emptyMap();
}
return this.getEncryptParams(method);
}

/**
* 获取映射方法
*
* @param mappedStatementId 映射语句 ID
* @param parameterCount 参数数量
* @return 映射方法
*/
private Method getMethod(String mappedStatementId, Integer parameterCount) {
try {
String className = CharSequenceUtil.subBefore(mappedStatementId, StringConstants.DOT, true);
String wrapperMethodName = CharSequenceUtil.subAfter(mappedStatementId, StringConstants.DOT, true);
String methodName = Stream.of("_mpCount", "_COUNT")
.filter(wrapperMethodName::endsWith)
.findFirst()
.map(suffix -> wrapperMethodName.substring(0, wrapperMethodName.length() - suffix.length()))
.orElse(wrapperMethodName);
// 获取真实方法
Optional<Method> methodOptional = Arrays.stream(ReflectUtil.getMethods(Class.forName(className), m -> {
if (parameterCount != null) {
return Objects.equals(m.getName(), methodName) && m.getParameterCount() == parameterCount;
}
return Objects.equals(m.getName(), methodName);
})).findFirst();
return methodOptional.orElse(null);
} catch (ClassNotFoundException e) {
throw new BusinessException(e.getMessage());
}
}

/**
* 获取加密参数列表
*
* @param method 方法
* @return 加密参数列表
*/
private Map<String, FieldEncrypt> getEncryptParams(Method method) {
// 获取方法中的加密参数
Map<String, FieldEncrypt> map = MapUtil.newHashMap();
Parameter[] parameterArr = method.getParameters();
for (int i = 0; i < parameterArr.length; i++) {
Parameter parameter = parameterArr[i];
String parameterName = this.getParameterName(parameter);
FieldEncrypt fieldEncrypt = parameter.getAnnotation(FieldEncrypt.class);
if (null != fieldEncrypt) {
map.put(parameterName, fieldEncrypt);
if (String.class.equals(parameter.getType())) {
map.put("param" + (i + 1), fieldEncrypt);
}
} else if (parameterName.startsWith(Constants.ENTITY)) {
map.put(parameterName, null);
} else if (parameterName.startsWith(Constants.WRAPPER)) {
map.put(parameterName, null);
}
}
return map;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
* @since 1.4.0
*/
@Intercepts({@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})})
public class MyBatisDecryptInterceptor extends AbstractMyBatisInterceptor {
public class MyBatisDecryptInterceptor extends AbstractMyBatisInterceptor implements Interceptor {

private CryptoProperties properties;

Expand Down Expand Up @@ -65,6 +65,9 @@ public Object intercept(Invocation invocation) throws Throwable {
for (Field field : fieldList) {
IEncryptor encryptor = super.getEncryptor(field.getAnnotation(FieldEncrypt.class));
Object fieldValue = ReflectUtil.getFieldValue(result, field);
if (null == fieldValue) {
continue;
}
// 优先获取自定义对称加密算法密钥,获取不到时再获取全局配置
String password = ObjectUtil.defaultIfBlank(field.getAnnotation(FieldEncrypt.class)
.password(), properties.getPassword());
Expand Down
Loading

0 comments on commit e9b81f9

Please sign in to comment.