mirror of
https://github.com/continew-org/continew-starter.git
synced 2025-09-09 20:57:23 +08:00
refactor(security/crypto): 优化字段加解密相关代码
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
|
||||
package top.continew.starter.security.crypto.core;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import org.apache.ibatis.executor.resultset.ResultSetHandler;
|
||||
@@ -24,6 +25,8 @@ import org.apache.ibatis.plugin.Intercepts;
|
||||
import org.apache.ibatis.plugin.Invocation;
|
||||
import org.apache.ibatis.plugin.Signature;
|
||||
import org.apache.ibatis.type.SimpleTypeRegistry;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import top.continew.starter.security.crypto.annotation.FieldEncrypt;
|
||||
import top.continew.starter.security.crypto.autoconfigure.CryptoProperties;
|
||||
import top.continew.starter.security.crypto.encryptor.IEncryptor;
|
||||
@@ -41,6 +44,7 @@ import java.util.List;
|
||||
@Intercepts({@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})})
|
||||
public class MyBatisDecryptInterceptor extends AbstractMyBatisInterceptor implements Interceptor {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(MyBatisDecryptInterceptor.class);
|
||||
private CryptoProperties properties;
|
||||
|
||||
public MyBatisDecryptInterceptor(CryptoProperties properties) {
|
||||
@@ -53,31 +57,73 @@ public class MyBatisDecryptInterceptor extends AbstractMyBatisInterceptor implem
|
||||
@Override
|
||||
public Object intercept(Invocation invocation) throws Throwable {
|
||||
Object obj = invocation.proceed();
|
||||
if (null == obj || !(invocation.getTarget() instanceof ResultSetHandler)) {
|
||||
if (obj == null) {
|
||||
return null;
|
||||
}
|
||||
// 确保目标是 ResultSetHandler
|
||||
if (!(invocation.getTarget() instanceof ResultSetHandler)) {
|
||||
return obj;
|
||||
}
|
||||
List<?> resultList = (List<?>)obj;
|
||||
// 处理查询结果
|
||||
if (obj instanceof List<?> resultList) {
|
||||
// 处理列表结果
|
||||
this.decryptList(resultList);
|
||||
} else {
|
||||
// 处理单个对象结果
|
||||
this.decryptObject(obj);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密列表结果
|
||||
*
|
||||
* @param resultList 结果列表
|
||||
*/
|
||||
private void decryptList(List<?> resultList) {
|
||||
if (CollUtil.isEmpty(resultList)) {
|
||||
return;
|
||||
}
|
||||
for (Object result : resultList) {
|
||||
// String、Integer、Long 等简单类型对象无需处理
|
||||
if (SimpleTypeRegistry.isSimpleType(result.getClass())) {
|
||||
decryptObject(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密单个对象结果
|
||||
*
|
||||
* @param result 结果对象
|
||||
*/
|
||||
private void decryptObject(Object result) {
|
||||
if (result == null) {
|
||||
return;
|
||||
}
|
||||
// String、Integer、Long 等简单类型对象无需处理
|
||||
if (SimpleTypeRegistry.isSimpleType(result.getClass())) {
|
||||
return;
|
||||
}
|
||||
// 获取所有字符串类型、需要解密的、有值字段
|
||||
List<Field> fieldList = super.getEncryptFields(result);
|
||||
if (fieldList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
// 解密处理
|
||||
for (Field field : fieldList) {
|
||||
IEncryptor encryptor = super.getEncryptor(field.getAnnotation(FieldEncrypt.class));
|
||||
Object fieldValue = ReflectUtil.getFieldValue(result, field);
|
||||
if (fieldValue == null) {
|
||||
continue;
|
||||
}
|
||||
// 获取所有字符串类型、需要解密的、有值字段
|
||||
List<Field> fieldList = super.getEncryptFields(result);
|
||||
// 解密处理
|
||||
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());
|
||||
// 优先获取自定义对称加密算法密钥,获取不到时再获取全局配置
|
||||
String password = ObjectUtil.defaultIfBlank(field.getAnnotation(FieldEncrypt.class).password(), properties
|
||||
.getPassword());
|
||||
try {
|
||||
String ciphertext = encryptor.decrypt(fieldValue.toString(), password, properties.getPrivateKey());
|
||||
ReflectUtil.setFieldValue(result, field, ciphertext);
|
||||
} catch (Exception e) {
|
||||
// 解密失败时保留原值,避免影响正常业务流程
|
||||
log.warn("解密失败,请检查加密配置", e);
|
||||
}
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
}
|
@@ -28,8 +28,9 @@ import org.apache.ibatis.mapping.BoundSql;
|
||||
import org.apache.ibatis.mapping.MappedStatement;
|
||||
import org.apache.ibatis.session.ResultHandler;
|
||||
import org.apache.ibatis.session.RowBounds;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import top.continew.starter.core.constant.StringConstants;
|
||||
import top.continew.starter.core.exception.BaseException;
|
||||
import top.continew.starter.security.crypto.annotation.FieldEncrypt;
|
||||
import top.continew.starter.security.crypto.autoconfigure.CryptoProperties;
|
||||
import top.continew.starter.security.crypto.encryptor.IEncryptor;
|
||||
@@ -50,6 +51,7 @@ import java.util.regex.Pattern;
|
||||
*/
|
||||
public class MyBatisEncryptInterceptor extends AbstractMyBatisInterceptor implements InnerInterceptor {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(MyBatisEncryptInterceptor.class);
|
||||
private static final Pattern PARAM_PAIRS_PATTERN = Pattern
|
||||
.compile("#\\{ew\\.paramNameValuePairs\\.(" + Constants.WRAPPER_PARAM + "\\d+)\\}");
|
||||
private final CryptoProperties properties;
|
||||
@@ -65,7 +67,7 @@ public class MyBatisEncryptInterceptor extends AbstractMyBatisInterceptor implem
|
||||
RowBounds rowBounds,
|
||||
ResultHandler resultHandler,
|
||||
BoundSql boundSql) {
|
||||
if (null == parameterObject) {
|
||||
if (parameterObject == null) {
|
||||
return;
|
||||
}
|
||||
if (parameterObject instanceof Map parameterMap) {
|
||||
@@ -75,7 +77,7 @@ public class MyBatisEncryptInterceptor extends AbstractMyBatisInterceptor implem
|
||||
|
||||
@Override
|
||||
public void beforeUpdate(Executor executor, MappedStatement mappedStatement, Object parameterObject) {
|
||||
if (null == parameterObject) {
|
||||
if (parameterObject == null) {
|
||||
return;
|
||||
}
|
||||
if (parameterObject instanceof Map parameterMap) {
|
||||
@@ -87,6 +89,60 @@ public class MyBatisEncryptInterceptor extends AbstractMyBatisInterceptor implem
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密查询参数(针对 Map 类型参数)
|
||||
*
|
||||
* @param parameterMap 参数
|
||||
* @param mappedStatement 映射语句
|
||||
*/
|
||||
private void encryptQueryParameter(Map<String, Object> parameterMap, MappedStatement mappedStatement) {
|
||||
Map<String, FieldEncrypt> encryptParameterMap = super.getEncryptParameters(mappedStatement);
|
||||
for (Map.Entry<String, Object> parameterEntrySet : parameterMap.entrySet()) {
|
||||
String parameterName = parameterEntrySet.getKey();
|
||||
Object parameterValue = parameterEntrySet.getValue();
|
||||
if (parameterValue == null || ClassUtil.isBasicType(parameterValue
|
||||
.getClass()) || parameterValue instanceof AbstractWrapper) {
|
||||
continue;
|
||||
}
|
||||
if (parameterValue instanceof String str) {
|
||||
FieldEncrypt fieldEncrypt = encryptParameterMap.get(parameterName);
|
||||
if (fieldEncrypt != null) {
|
||||
parameterMap.put(parameterName, this.doEncrypt(str, fieldEncrypt));
|
||||
}
|
||||
} else {
|
||||
// 实体参数
|
||||
this.encryptEntity(super.getEncryptFields(parameterValue), parameterValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理实体加密
|
||||
*
|
||||
* @param fieldList 加密字段列表
|
||||
* @param entity 实体
|
||||
*/
|
||||
private void encryptEntity(List<Field> fieldList, Object entity) {
|
||||
for (Field field : fieldList) {
|
||||
IEncryptor encryptor = super.getEncryptor(field.getAnnotation(FieldEncrypt.class));
|
||||
Object fieldValue = ReflectUtil.getFieldValue(entity, field);
|
||||
if (fieldValue == null) {
|
||||
continue;
|
||||
}
|
||||
// 优先获取自定义对称加密算法密钥,获取不到时再获取全局配置
|
||||
String password = ObjectUtil.defaultIfBlank(field.getAnnotation(FieldEncrypt.class).password(), properties
|
||||
.getPassword());
|
||||
String ciphertext = fieldValue.toString();
|
||||
try {
|
||||
ciphertext = encryptor.encrypt(fieldValue.toString(), password, properties.getPublicKey());
|
||||
} catch (Exception e) {
|
||||
// 加密失败时保留原值,避免影响正常业务流程
|
||||
log.warn("加密失败,请检查加密配置", e);
|
||||
}
|
||||
ReflectUtil.setFieldValue(entity, field, ciphertext);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密 Map 类型数据(使用 @Param 注解的场景)
|
||||
*
|
||||
@@ -105,33 +161,6 @@ public class MyBatisEncryptInterceptor extends AbstractMyBatisInterceptor implem
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密查询参数(针对 Map 类型参数)
|
||||
*
|
||||
* @param parameterMap 参数
|
||||
* @param mappedStatement 映射语句
|
||||
*/
|
||||
private void encryptQueryParameter(Map<String, Object> parameterMap, MappedStatement mappedStatement) {
|
||||
Map<String, FieldEncrypt> encryptParameterMap = super.getEncryptParameters(mappedStatement);
|
||||
for (Map.Entry<String, Object> parameterEntrySet : parameterMap.entrySet()) {
|
||||
String parameterName = parameterEntrySet.getKey();
|
||||
Object parameterValue = parameterEntrySet.getValue();
|
||||
if (null == parameterValue || ClassUtil.isBasicType(parameterValue
|
||||
.getClass()) || parameterValue instanceof AbstractWrapper) {
|
||||
continue;
|
||||
}
|
||||
if (parameterValue instanceof String str) {
|
||||
FieldEncrypt fieldEncrypt = encryptParameterMap.get(parameterName);
|
||||
if (fieldEncrypt != null) {
|
||||
parameterMap.put(parameterName, this.doEncrypt(str, fieldEncrypt));
|
||||
}
|
||||
} else {
|
||||
// 实体参数
|
||||
this.encryptEntity(super.getEncryptFields(parameterValue), parameterValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 UpdateWrapper 类型参数加密(针对 MP 的 UpdateWrapper、LambdaUpdateWrapper 等参数)
|
||||
*
|
||||
@@ -156,7 +185,7 @@ public class MyBatisEncryptInterceptor extends AbstractMyBatisInterceptor implem
|
||||
propMap.put(elPart[0], elPart[1]);
|
||||
});
|
||||
// 获取加密字段
|
||||
Class<?> entityClass = mappedStatement.getParameterMap().getType();
|
||||
Class<?> entityClass = this.getEntityClass(updateWrapper, mappedStatement);
|
||||
List<Field> encryptFieldList = super.getEncryptFields(entityClass);
|
||||
for (Field field : encryptFieldList) {
|
||||
FieldEncrypt fieldEncrypt = field.getAnnotation(FieldEncrypt.class);
|
||||
@@ -175,32 +204,6 @@ public class MyBatisEncryptInterceptor extends AbstractMyBatisInterceptor implem
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理实体加密
|
||||
*
|
||||
* @param fieldList 加密字段列表
|
||||
* @param entity 实体
|
||||
*/
|
||||
private void encryptEntity(List<Field> fieldList, Object entity) {
|
||||
for (Field field : fieldList) {
|
||||
IEncryptor encryptor = super.getEncryptor(field.getAnnotation(FieldEncrypt.class));
|
||||
Object fieldValue = ReflectUtil.getFieldValue(entity, field);
|
||||
if (null == fieldValue) {
|
||||
continue;
|
||||
}
|
||||
// 优先获取自定义对称加密算法密钥,获取不到时再获取全局配置
|
||||
String password = ObjectUtil.defaultIfBlank(field.getAnnotation(FieldEncrypt.class).password(), properties
|
||||
.getPassword());
|
||||
String ciphertext;
|
||||
try {
|
||||
ciphertext = encryptor.encrypt(fieldValue.toString(), password, properties.getPublicKey());
|
||||
} catch (Exception e) {
|
||||
throw new BaseException(e);
|
||||
}
|
||||
ReflectUtil.setFieldValue(entity, field, ciphertext);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理加密
|
||||
*
|
||||
@@ -208,7 +211,7 @@ public class MyBatisEncryptInterceptor extends AbstractMyBatisInterceptor implem
|
||||
* @param fieldEncrypt 字段加密注解
|
||||
*/
|
||||
private Object doEncrypt(Object parameterValue, FieldEncrypt fieldEncrypt) {
|
||||
if (null == parameterValue) {
|
||||
if (parameterValue == null) {
|
||||
return null;
|
||||
}
|
||||
IEncryptor encryptor = super.getEncryptor(fieldEncrypt);
|
||||
@@ -217,7 +220,26 @@ public class MyBatisEncryptInterceptor extends AbstractMyBatisInterceptor implem
|
||||
try {
|
||||
return encryptor.encrypt(parameterValue.toString(), password, properties.getPublicKey());
|
||||
} catch (Exception e) {
|
||||
throw new BaseException(e);
|
||||
// 加密失败时保留原值,避免影响正常业务流程
|
||||
log.warn("加密失败,请检查加密配置", e);
|
||||
}
|
||||
return parameterValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体类
|
||||
*
|
||||
* @param wrapper 查询或更新包装器
|
||||
* @param mappedStatement 映射语句
|
||||
* @return 实体类
|
||||
*/
|
||||
private Class<?> getEntityClass(AbstractWrapper wrapper, MappedStatement mappedStatement) {
|
||||
// 尝试从 Wrapper 中获取实体类
|
||||
Class<?> entityClass = wrapper.getEntityClass();
|
||||
if (entityClass != null) {
|
||||
return entityClass;
|
||||
}
|
||||
// 从映射语句中获取实体类
|
||||
return mappedStatement.getParameterMap().getType();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user