From a4823dcb0bf211e26ccb8816928b5332b2bfe216 Mon Sep 17 00:00:00 2001 From: Charles7c Date: Mon, 9 Jun 2025 19:28:45 +0800 Subject: [PATCH] =?UTF-8?q?refactor(security/crypto):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E5=8A=A0=E8=A7=A3=E5=AF=86=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/MyBatisDecryptInterceptor.java | 80 +++++++--- .../core/MyBatisEncryptInterceptor.java | 140 ++++++++++-------- 2 files changed, 144 insertions(+), 76 deletions(-) diff --git a/continew-starter-security/continew-starter-security-crypto/src/main/java/top/continew/starter/security/crypto/core/MyBatisDecryptInterceptor.java b/continew-starter-security/continew-starter-security-crypto/src/main/java/top/continew/starter/security/crypto/core/MyBatisDecryptInterceptor.java index ed0cf135..fc993c09 100644 --- a/continew-starter-security/continew-starter-security-crypto/src/main/java/top/continew/starter/security/crypto/core/MyBatisDecryptInterceptor.java +++ b/continew-starter-security/continew-starter-security-crypto/src/main/java/top/continew/starter/security/crypto/core/MyBatisDecryptInterceptor.java @@ -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 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 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; } } \ No newline at end of file diff --git a/continew-starter-security/continew-starter-security-crypto/src/main/java/top/continew/starter/security/crypto/core/MyBatisEncryptInterceptor.java b/continew-starter-security/continew-starter-security-crypto/src/main/java/top/continew/starter/security/crypto/core/MyBatisEncryptInterceptor.java index 9474f334..da19b39e 100644 --- a/continew-starter-security/continew-starter-security-crypto/src/main/java/top/continew/starter/security/crypto/core/MyBatisEncryptInterceptor.java +++ b/continew-starter-security/continew-starter-security-crypto/src/main/java/top/continew/starter/security/crypto/core/MyBatisEncryptInterceptor.java @@ -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 parameterMap, MappedStatement mappedStatement) { + Map encryptParameterMap = super.getEncryptParameters(mappedStatement); + for (Map.Entry 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 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 parameterMap, MappedStatement mappedStatement) { - Map encryptParameterMap = super.getEncryptParameters(mappedStatement); - for (Map.Entry 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 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 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(); } }