Mybatis使用拦截器实现数据的加解密

本文介绍了如何在Mybatis中使用自定义拦截器对Mapper层的特定方法进行加解密操作,以保护敏感数据。通过配置拦截器并在MySQL中使用加密函数AES_ENCRYPT和AES_DECRYPT进行数据加密和解密。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Mybatis使用拦截器实现数据的加解密

实现思路

  1. mybatis配置类中加入自定义拦截器
  2. 自定义拦截器对指定mapper层指定方法(修改或新增相关业务表的方法)进行拦截,对指定属性或字段进行加解密操作

实现代码

// Copyright 2016-2101 Pica.
package com.pica.cloud.patient.health.server.annotation;

import com.google.common.collect.Lists;
import com.pica.cloud.foundation.entity.PicaWarnException;
import com.pica.cloud.patient.health.common.enums.HealthResultCode;
import com.pica.cloud.patient.health.common.utils.EncryptUtils;
import com.pica.cloud.patient.health.server.entity.*;
import com.pica.cloud.patient.health.server.model.patient.PatDocPatModel;
import com.pica.cloud.patient.health.server.util.EmojiFilterUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;

import java.lang.reflect.Field;
import java.util.*;

/**
 * 加密patient patientInfo中的昵称和身份证号
 *
 * @ClassName EncryptNameIdInterceptor
 * @Description
 * @Author Chongwen.jiang
 * @Date 2019/4/3 11:31
 * @ModifyDate 2019/4/3 11:31
 * @Version 1.0
 */
@Intercepts({
   
   @Signature(type = Executor.class, method = "update", args = {
   
   MappedStatement.class, Object.class})})
public class EncryptNameIdInterceptor implements Interceptor {
   
   

    private static final List<String> handlerMethod = Lists.newArrayList(
            "com.pica.cloud.patient.server.mapper.PatPatientInfoMapper.updateByPrimaryKeySelective",
            "com.pica.cloud.patient.server.mapper.PatPatientInfoMapper.insertBatchPatientInfo",
            "com.pica.cloud.patient.server.mapper.PatPatientInfoMapper.updateByExampleSelective",
            "com.pica.cloud.patient.server.mapper.PatPatientMapper.insertBatchPatientBasic",
            "com.pica.cloud.patient.server.mapper.PatHospitalPatInfoMapper.insertBatch",
            "com.pica.cloud.patient.server.mapper.PatHospitalPatInfoMapper.batchUpdate",
            "com.pica.cloud.patient.server.mapper.PatDocPatInfoMapper.insertBatch"
    );

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
   
   
        final MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        Executor executor = (Executor) invocation.getTarget();
        Object parameter;
        boolean isEncrypted = false;
        parameter = invocation.getArgs()[1];
        BoundSql boundSql = mappedStatement.getBoundSql(parameter);
        //只处理patientInfo 和patient 的mapper里面相关的sql
        if (parameter instanceof PatPatientInfo || parameter instanceof PatPatient || parameter instanceof PatientInfo
                || parameter instanceof PatHospitalPatInfo || parameter instanceof PatDocPatMapping
                || parameter instanceof PatDocPatInfo || parameter instanceof PatDocPatModel
                || handlerMethod.contains(mappedStatement.getId())) {
   
   
            Object obj = boundSql.getParameterObject();
            // 加密处理
            isEncrypted = dealPatientValue(obj, true, parameter);
        }

        Object result = executor.update(mappedStatement, parameter);
        if (isEncrypted) {
   
   
            //防止多次使用同一个对象,导致字段被多次加密
            Object obj = boundSql.getParameterObject();
            dealPatientValue(obj, false, parameter);
        }
        return result;
    }

    private boolean dealPatientValue(Object obj, boolean encryptFlag, Object parameter) throws IllegalAccessException {
   
   
        boolean isEncrypted = false;
        if (obj != null) {
   
   
            if (parameter instanceof Map) {
   
   
                Map
### MyBatis 拦截器实现 SM4 加密解密 #### 设计思路 为了实现MyBatis中对指定字段进行自动加解密操作,设计了一种基于拦截器和自定义注解的方法。该方法允许开发者标记哪些字段需要被加密或解码,在数据存入数据库之前对其进行加密处理,并在读取时将其转换回原始形式。 #### 自定义注解 `@Encryption` 创建一个新的Java注解`@Encryption`,用于标注那些希望应用SM4算法来保护其隐私性的实体类属性: ```java import java.lang.annotation.*; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Encryption { String encryptionType() default "SM4"; } ``` 此段代码定义了一个名为`Encryption`的元注解,它能够应用于成员变量级别并保留至运行时期间以便后续访问[^4]。 #### 创建拦截器 接下来构建一个实现了`Interceptor`接口的具体类——`Sm4EncryptDecryptInterceptor`. 这个组件负责监听SQL执行过程中的关键事件点(如参数设置前、结果集映射后),从而有机会修改即将发送给DBMS的数据包以及接收到的结果记录。 ```java package com.example.interceptor; import org.apache.ibatis.executor.parameter.ParameterHandler; import org.apache.ibatis.plugin.*; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.util.Properties; @Intercepts({ @Signature(type = ParameterHandler.class, method = "setParameters", args = {PreparedStatement.class}) }) public class Sm4EncryptDecryptInterceptor implements Interceptor { private static final String ALGORITHM_NAME = "SM4"; @Override public Object intercept(Invocation invocation) throws Throwable { // 获取当前正在处理的对象实例 ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget(); // 对应于目标对象所属类型的Class描述符 Class<?> targetClass = parameterHandler.getParameterObject().getClass(); Field[] fields = targetClass.getDeclaredFields(); for (Field field : fields){ if(field.isAnnotationPresent(Encryption.class)){ field.setAccessible(true); SecretKeySpec secretKey = new SecretKeySpec("your-secret-key".getBytes(), ALGORITHM_NAME); Cipher cipher = Cipher.getInstance(ALGORITHM_NAME); Object value = field.get(parameterHandler.getParameterObject()); if(value != null && !value.toString().isEmpty()){ byte[] encryptedValueBytes = encryptOrDecrypt(cipher,secretKey,value.toString(),"ENCRYPT"); // 将原值替换为经过加密后的版本 field.set(parameterHandler.getParameterObject(), Base64.getEncoder().encodeToString(encryptedValueBytes)); } } } return invocation.proceed(); } private byte[] encryptOrDecrypt(Cipher cipher,SecretKeySpec keySpec,Object data,String mode)throws Exception{ int opMode = mode.equals("DECRYPT") ? Cipher.DECRYPT_MODE:Cipher.ENCRYPT_MODE ; cipher.init(opMode,keySpec); return cipher.doFinal(data.toString().getBytes(StandardCharsets.UTF_8)); } @Override public void setProperties(Properties properties) {} @Override public Object plugin(Object target) { return Plugin.wrap(target,this); } } ``` 上述代码片段展示了如何编写一个简单的MyBatis插件,它可以识别带有`@Encryption`标签的目标域,并在其准备写入持久化层之前对其内容实施编码变换。注意这里仅提供了基本框架,实际部署还需要考虑更多细节比如异常捕获逻辑优化等[^1]。 对于查询操作而言,则需另外注册一个专门用来解析ResultSet的处理器,确保从数据库取出的信息能顺利还原成未加密状态下的表示形式。这部分工作可以通过扩展`ResultHandler`完成,不过具体实现方式会依赖于项目架构和个人偏好而有所不同。 #### 配置文件调整 最后一步是在应用程序启动阶段加载所编写的中间件模块。这通常涉及到编辑Spring Boot项目的application.yml或者XML格式化的mybatis-config.xml文档,向其中加入如下所示的内容: ```yaml mybatis: configuration: plugins: - interceptor: com.example.interceptor.Sm4EncryptDecryptInterceptor ``` 这样就完成了整个流程的设计与开发,使得任何被打上了适当标志位的POJO成员都能够享受到透明式的安全防护措施[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值