当前位置: 首页 > news >正文

MyBatis拦截器插件:实现敏感数据字段加解密

文章目录

  • 一、写在前面
  • 二、编码实现
    • 1、注解
    • 2、拦截器插件
    • 3、配置插件
    • 4、实体类
    • 5、测试
  • 三、扩展
    • 1、优化点

一、写在前面

日常开发中,经常有一些敏感数据,直接写入数据库的话,很容易泄露。
本文基于mybatis拦截器插件,实现敏感数据的加解密。

二、编码实现

1、注解

import java.lang.annotation.*;@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EncryptedField {String algorithm() default "AES";
}

2、拦截器插件


import com.example.encryption.annotation.EncryptedField;
import com.example.encryption.service.EncryptionService;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.util.Properties;@Component
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, org.apache.ibatis.session.RowBounds.class, org.apache.ibatis.session.ResultHandler.class})
})
public class EncryptDecryptInterceptor implements Interceptor {@Autowiredprivate EncryptionService encryptionService;@Overridepublic Object intercept(Invocation invocation) throws Throwable {MappedStatement ms = (MappedStatement) invocation.getArgs()[0];Object parameter = invocation.getArgs()[1];// 加密处理 INSERT/UPDATEif (ms.getSqlCommandType() == SqlCommandType.INSERT || ms.getSqlCommandType() == SqlCommandType.UPDATE) {handleEncryption(parameter);}Object result = invocation.proceed();// 解密处理 SELECTif (ms.getSqlCommandType() == SqlCommandType.SELECT) {handleDecryption(result);}return result;}private void handleEncryption(Object parameter) throws Exception {if (parameter == null) return;for (Field field : parameter.getClass().getDeclaredFields()) {if (field.isAnnotationPresent(EncryptedField.class)) {field.setAccessible(true);Object value = field.get(parameter);if (value instanceof String) {field.set(parameter, encryptionService.encrypt((String) value));}}}}private void handleDecryption(Object result) throws Exception {if (result == null) return;if (result instanceof java.util.Collection) {for (Object obj : (java.util.Collection<?>) result) {decryptObject(obj);}} else {decryptObject(result);}}private void decryptObject(Object obj) throws Exception {for (Field field : obj.getClass().getDeclaredFields()) {if (field.isAnnotationPresent(EncryptedField.class)) {field.setAccessible(true);Object value = field.get(obj);if (value instanceof String) {field.set(obj, encryptionService.decrypt((String) value));}}}}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {}
}

3、配置插件

import com.example.encryption.interceptor.EncryptDecryptInterceptor;
import org.mybatis.spring.boot.autoconfigure.ConfigurationCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class MyBatisConfig {@Beanpublic ConfigurationCustomizer configurationCustomizer(EncryptDecryptInterceptor interceptor) {return configuration -> configuration.addInterceptor(interceptor);}
}

4、实体类


import com.example.encryption.annotation.EncryptedField;public class User {private Long id;private String username;@EncryptedFieldprivate String idCard;@EncryptedFieldprivate String phoneNumber;// Getters and Setterspublic Long getId() { return id; }public void setId(Long id) { this.id = id; }public String getUsername() { return username; }public void setUsername(String username) { this.username = username; }public String getIdCard() { return idCard; }public void setIdCard(String idCard) { this.idCard = idCard; }public String getPhoneNumber() { return phoneNumber; }public void setPhoneNumber(String phoneNumber) { this.phoneNumber = phoneNumber; }// toString@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", idCard='" + idCard + '\'' +", phoneNumber='" + phoneNumber + '\'' +'}';}}

5、测试


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;import com.example.encryption.entity.User;
import com.example.encryption.mapper.UserMapper;@SpringBootApplication
public class EncryptionDemoApplication {public static void main(String[] args) {ConfigurableApplicationContext run = SpringApplication.run(EncryptionDemoApplication.class, args);UserMapper userMapper = run.getBean(UserMapper.class);// 增User user = new User();user.setId(1L);user.setUsername("test1");user.setIdCard("111111111111");user.setPhoneNumber("1311111");userMapper.insert(user);System.out.println(userMapper.selectById(1L));;// 改user.setUsername("test2");user.setIdCard("2222222222");user.setPhoneNumber("1322222222");userMapper.updateById(user);System.out.println(userMapper.selectById(1L));;System.out.println(userMapper.selectById(1L));;}
}

在这里插入图片描述

三、扩展

1、优化点

1、插件使用反射对类进行赋值、获取值,为了提高性能,可以考虑将字段进行缓存(使用ConcurrentHashMap)
2、加解密方法,可以考虑扩展成接口,加密方式可扩展。
3、本内容只支持MyBatis简单场景,MyBatisPlus、分页场景、参数为List、Map或者复杂对象,需要对参数进一步递归处理。

http://www.lryc.cn/news/596248.html

相关文章:

  • 汽车安全 | 汽车安全入门
  • 力扣刷题 -- 101.对称二叉树
  • 贪心算法Day3学习心得
  • LeetCode 刷题【11. 盛最多水的容器】
  • 数据库 × 缓存双写策略深度剖析:一致性如何保障?
  • 《3D printed deformable sensors》论文解读
  • EasyMan 数字人服务全面焕新,交互型AI数字人助推孪生体验全新升级
  • GoLang教程006:循环控制语句
  • 数据结构 之 【排序】(直接选择排序、堆排序、冒泡排序)
  • 自编码器表征学习:重构误差与隐空间拓扑结构的深度解析
  • Dockerfile 详解
  • 鸿蒙卡片开发保姆级教程
  • AI创作系列第22篇:前端缓存与更新机制重构 - 表情包系统的全面升级
  • anchor 智能合约案例6 之 token_lottery
  • 假发行业数字化突围,外贸ERP重构外协管理引擎,助力效率飞跃
  • 34、鸿蒙Harmony Next开发:使用动画-转场动画
  • Jmeter使用 - 2
  • Chrome 开发环境屏蔽 CORS 跨域限制
  • PHICOMM(斐讯)N1盒子 - Armbian25.05(Debian 12)刷入U盘/EMMC
  • SQL 中 JOIN 顺序对性能的影响
  • FastDFS 6.11.0 单机环境搭建与测试(附 Nginx 集成)+ docker构建+k8s启动文件
  • 浏览器地址栏输入URL回车后白屏分析
  • Jenkins接口自动化测试(构建)平台搭建
  • Apache Ignite 中事务的使用方式和机制
  • Excel工具
  • ROS个人笔记
  • Qt Creator集成开发环境使用指南
  • K 近邻算法(K-Nearest Neighbors, KNN)详解及案例
  • 聊聊原生 CSS 变量:让样式更灵活的“魔法”
  • 大模型推理环境安装过程中踩坑记录