Mybatis加密解密查询操作(sql前),where要传入加密后的字段时遇到的问题

项目场景:

提示:这里简述项目相关背景:

例如:Mybatis加密解密查询操作(sql前),where要传入加密后的字段时遇到的问题


问题描述

提示:这里描述项目中遇到的问题:

例如:数据传输过程中数据不时出现丢失的情况,偶尔会丢失一部分数据

APP 中接收数据代码:

c 复制代码
public Object intercept(Invocation invocation) throws Throwable {
        ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget();

        // 获取传入的参数对象
        Object parameterObject = parameterHandler.getParameterObject();

        if (parameterObject instanceof Map) {
            Map<?, ?> paramMap = (Map<?, ?>) parameterObject;
            for (Map.Entry<?, ?> entry : paramMap.entrySet()) {
                Object key = entry.getKey();
                Object value = entry.getValue();

                // 对于带有 @Sensitive 注解的字段,进行加密处理
                if (value != null && !value.toString().isEmpty()) {  // 判空和空字符串检查
                    // 反射检查该字段是否标记了 @Sensitive 注解
                    if (isSensitiveField(value)) {
                        String encryptedValue = SensitiveDataUtils.encrypt(value.toString(), SM4_KEY);
                        ((Map<Object, Object>) paramMap).put(key, encryptedValue);
                    }
                }
            }
        } else {
            // 处理非 Map 类型的参数(如单个对象查询)
            encryptSensitiveFields(parameterObject);
        }

        // 执行原始逻辑
        return invocation.proceed();
    }
这个方法有问题啊

原因分析:

提示:这里填写问题的分析:

是的,这个 intercept 方法存在几个潜在问题,可能导致在处理加密字段时出现错误。以下是详细的分析和改进建议:

  1. parameterObject 为 Map 类型时的处理
    在你当前的代码中,如果 parameterObject 是 Map 类型,会迭代其中的 key-value 对并检查每个 value 是否标记了 @Sensitive 注解,进而进行加密处理。这里有几个潜在问题:

value 可能是复杂对象:目前的判断条件是 if (value != null && !value.toString().isEmpty()),但是 value 可能是一个复杂对象(例如 User 对象),而不是一个简单的 String 类型。在这种情况下,直接使用 value.toString() 可能并不能反映实际字段的内容。

isSensitiveField 反射问题:你尝试通过反射检查 value 是否包含 @Sensitive 注解,但是 value 很可能是一个普通的 Java 对象(如 AdminUserDO),直接传给 isSensitiveField 可能会导致反射错误。

  1. parameterObject 不是 Map 类型时的处理

    如果 parameterObject 不是 Map 类型,你使用 encryptSensitiveFields(parameterObject) 来处理加密。该方法会检查对象中的字段并加密被 @Sensitive 注解标记的字段。问题在于,你并没有考虑 parameterObject 可能是一个嵌套对象,或者该对象的类型可能没有适当的 getter 方法,导致反射出错。

  2. 改进建议

    我们需要确保在处理 Map 类型和非 Map 类型的参数时,都能正确处理嵌套对象和字段加密。


解决方案:

提示:这里填写该问题的具体解决方案:

复制代码
package cn.iocoder.yudao.framework.mybatis.core.handler;

import cn.iocoder.yudao.framework.annotation.Sensitive;
import cn.iocoder.yudao.framework.mybatis.core.util.SensitiveDataUtils;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.plugin.*;

import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.util.Map;

import static cn.iocoder.yudao.framework.mybatis.core.util.SensitiveDataUtils.SM4_KEY;

@Intercepts({
        @Signature(type = ParameterHandler.class, method = "setParameters", args = {PreparedStatement.class})
})
public class SensitiveDataEncryptInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget();

        // 获取传入的参数对象
        Object parameterObject = parameterHandler.getParameterObject();

        // 如果是 Map 类型的参数
        if (parameterObject instanceof Map) {
            Map<?, ?> paramMap = (Map<?, ?>) parameterObject;
            for (Map.Entry<?, ?> entry : paramMap.entrySet()) {
                Object key = entry.getKey();
                Object value = entry.getValue();

                // 判断 value 是否为带有 @Sensitive 注解的字段,进行加密处理
                if (value != null) {
                    // 对 value 进行加密
                    String encryptedValue = encryptSensitiveValue(value);
                    // 如果字段需要加密,替换 Map 中的值
                    if (encryptedValue != null) {
                        // 强制转换为 Map<Object, Object> 来避免类型问题
                        ((Map<Object, Object>) paramMap).put(key, encryptedValue);
                    }
                }
            }
        } else {
            // 如果不是 Map 类型,处理对象的字段加密
            encryptSensitiveFields(parameterObject);
        }

        // 执行原始逻辑
        return invocation.proceed();
    }

    private String encryptSensitiveValue(Object value) throws Exception {
        if (value instanceof String && isSensitiveField(value)) {
            // 对象字段加密处理
            return SensitiveDataUtils.encrypt(value.toString(), SM4_KEY);
        }
        return null;
    }

    private boolean isSensitiveField(Object value) {
        // 判断该对象字段是否带有 @Sensitive 注解
        Class<?> clazz = value.getClass();
        for (Field field : clazz.getDeclaredFields()) {
            if (field.isAnnotationPresent(Sensitive.class)) {
                return true;  // 该字段带有 @Sensitive 注解
            }
        }
        return false;
    }

    private void encryptSensitiveFields(Object parameterObject) throws Exception {
        // 遍历对象的字段,检查是否带有 @Sensitive 注解
        Field[] fields = parameterObject.getClass().getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(Sensitive.class)) {
                field.setAccessible(true);
                Object value = field.get(parameterObject);
                if (value != null) {
                    String encryptedValue = SensitiveDataUtils.encrypt(value.toString(), SM4_KEY);
                    field.set(parameterObject, encryptedValue);
                }
            }
        }
    }
}

主要改进点:

encryptSensitiveValue 方法:

这个方法首先检查传入的 value 是否是需要加密的字段,如果是,则进行加密。

通过调用 isSensitiveField(value) 来判断是否需要加密,而不直接依赖 value.toString()。

isSensitiveField 方法:

通过反射检查 value 对象是否包含带有 @Sensitive 注解的字段。之前可能存在错误的反射逻辑,这里是基于对象字段的反射检查。

encryptSensitiveFields 方法:

遍历 parameterObject 的字段,并加密带有 @Sensitive 注解的字段。处理对象字段时,直接通过反射获取字段并进行加密。

其他注意事项:

确保 SensitiveDataUtils.encrypt 方法能够正确处理所有类型的 value,尤其是对于非 String 类型的对象,可能需要进一步优化加密处理。

如果 parameterObject 是一个复杂的对象,确保该对象的所有字段都可以通过反射访问(即字段为 public 或者使用了 setAccessible(true))。

这样修改后,应该能够有效避免反射错误并正确处理加密逻辑。

相关推荐
oradh4 分钟前
Oracle数据库网络体系结构概述
数据库·oracle·数据库基础·数据库入门·oracle网络基础
满天星830357710 分钟前
【MySQL】表的基本查询(上)
linux·服务器·数据库·mysql
主角1 717 分钟前
MySQL高可用集群
数据库·mysql
dajun18112345623 分钟前
信息系统运维管理全流程详解 在线画图工具绘制运维流程图表技巧
运维·数据库·信息可视化·流程图·旅游·论文笔记
流觞 无依25 分钟前
SQLite数据库损坏修复指南——解决“database disk image is malformed”报错
jvm·数据库·sqlite
道清茗26 分钟前
【MySQL知识点问答题】 安全与性能管理
数据库·mysql
2501_9206276133 分钟前
Flutter 框架跨平台鸿蒙开发 - 数据库学习助手
数据库·学习·flutter·华为·harmonyos
ZStack开发者社区38 分钟前
阿里云 × ZStack:云端管得好,边端交付稳
数据库·边缘计算
TDengine (老段)39 分钟前
TDengine IDMP 可视化 —— 趋势图
大数据·数据库·人工智能·物联网·时序数据库·tdengine·涛思数据
万邦科技Lafite42 分钟前
淘宝关键词API接口获取分类商品信息指南
java·前端·数据库·开放api·淘宝开放平台