基于Mybatis插件方式实现数据脱敏处理
一、项目介绍
1、项目背景
有时候我们数据库中存储一些敏感的信息比如手机号、银行卡号,我们希望我们查询出来的的时候对一些敏感信息做一些脱敏处理。
当面项目是基于自定义Mybatis插件方式实现数据脱敏处理,通过插件拦截结果集进行脱敏后再返回,所以对于使用者透明,业务逻辑无感知。
目前支持用户名脱敏、手机号脱敏、座机号码脱敏、银行卡脱敏、身份证号脱敏、邮箱脱敏、地址脱敏。
2、注解说明
/**
* 对需要脱敏的字段加上该注解
*/
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
public @interface SensitiveField {
/**
* 脱敏类型
*/
SensitiveTypeEnums value();
/**
* 填充值
*/
String fillValue() default "*";
}
目前支持脱敏类型
/**
* 脱敏类型
*/
public enum SensitiveTypeEnums {
/**
* 默认方式脱敏
*/
DEFAULT(0,6),
/**
* 中文名称
*/
CHINESE_NAME(1,1),
/**
* 手机号
*/
MOBILE(3,4),
/**
* 座机号码
*/
FIXED_PHONE(0,4),
/**
* 银行卡
*/
BANK_CARD(6,4),
/**
* 身份证号
*/
ID_CARD(0,4),
/**
* 邮箱
*/
EMAIL(2,0),
/**
* 地址
*/
ADDRESS(6,4),
;
}
举例: 如11位的手机号,默认脱敏策略是显示(3,4)前三后四,如 13712345678 脱敏后变成 137****5678。
二、实现原理
1、该插件项目的原理
通过拦截器拦截Mybatis的select语句,通过自定义注解获取到需要脱敏处理的属性字段,并为该属性根据不同的脱敏类型进行脱敏,处理后再返回。
2、插件源码
/**
* 基于拦截器对数据脱敏
*
* @author xub
* @date 2022/6/2 下午2:23
*/
@Intercepts({
@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {java.sql.Statement.class})
})
public class DesensitizationInterceptor implements Interceptor {
private static final Logger log = LoggerFactory.getLogger(DesensitizationInterceptor.class);
/**
* key值为class对象 value可以理解成是该类带有SensitiveField注解的属性,只不过对属性封装了一层。
* 它是非常能够提高性能的处理器 它的作用就是不用每一次一个对象经来都要看下它的哪些属性带有SensitiveField注解
* 毕竟类的反射在性能上并不友好。只要key包含该对象那就不需要检查它哪些属性带SensitiveField注解。
*/
private Map<Class, List<Handler>> handlerMap = new ConcurrentHashMap<>();
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 获取结果
List<Object> results = (List<Object>) invocation.proceed();
if (CollectionUtils.isEmpty(results)) {
return results;
}
// 批量设置加密
for (Object object : results) {
process(object);
}
return results;
}
private void process(Object object) throws Throwable {
Class handlerKey = object.getClass();
List<Handler> handlerList = handlerMap.get(handlerKey);
//性能优化点,如果有两个都是user对象同时,那么只需有个进行反射处理属性就好了,另一个只需执行下面的for循环
SYNC:
if (handlerList == null) {
synchronized (this) {
handlerList = handlerMap.get(handlerKey);
//如果到这里map集合已经存在,则跳出到指定SYNC标签
if (handlerList != null) {
break SYNC;
}
handlerMap.put(handlerKey, handlerList = new ArrayList<>());
// 反射工具类 获取带有SensitiveField注解的所有属性字段
Set<Field> allFields = ReflectionUtils.getAllFields(
object.getClass(),
input -> input != null && input.getAnnotation(SensitiveField.class) != null
);
for (Field field : allFields) {
handlerList.add(new Handler(field));
}
}
}
for (Handler handler : handlerList) {
handler.accept(object);
}
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
private static class Handler {
Field field;
Handler(Field field) {
this.field = field;
}
private boolean checkField(Object object, Field field) throws IllegalAccessException {
if (!field.isAccessible()) {
field.setAccessible(true);
}
//如果为空 那么就不用进行脱敏操作了
return field.get(object) != null;
}
public void accept(Object o) throws Throwable {
if (checkField(o, field)) {
SensitiveField annotation = field.getAnnotation(SensitiveField.class);
SensitiveTypeEnums typeEnums = annotation.value();
String fillValue = annotation.fillValue();
Object o1 = field.get(o);
log.info("加密之前数据 = {}",o1);
SensitiveStrategy sensitiveStrategy = SensitiveContext.get(typeEnums);
String s = sensitiveStrategy.handle(o1, fillValue);
log.info("加密之后数据 = {}",s);
field.set(o, s);
}
}
}
}
三、使用方式
1、添加jar包
<dependency>
<groupId>com.jincou</groupId>
<artifactId>mybatis-sensitive-plugin-starter</artifactId>
<version>1.0.0</version>
</dependency>
2、User实体添加注解
/**
* 用户信息表
*/
@Data
public class User implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
private Integer id;
/**
* 姓名
*/
@SensitiveField(SensitiveTypeEnums.CHINESE_NAME)
private String name;
/**
* 邮箱
*/
@SensitiveField(SensitiveTypeEnums.EMAIL)
private String email;
/**
* 手机号
*/
@SensitiveField(SensitiveTypeEnums.MOBILE)
private String mobile;
/**
* 地址
*/
@SensitiveField(SensitiveTypeEnums.ADDRESS)
private String address;
}
3、请求接口
@RestController
public class TestController {
@Autowired
private UserMapper userMapper;
@GetMapping("/getById")
User get(Integer id){
return userMapper.selectByPrimaryKey(id);
}
@GetMapping("/findAllUser")
List<User> findAllUser(){
return userMapper.findAllUser();
}
}
请求接口url
http://localhost:8080/findAllUser
4、接口返回数据
[
{
"id":1,
"age":10,
"name":"z*****u",
"email":"45*******@qq.com",
"mobile":"137****2222",
"address":"宁波市慈溪市***********鸣鹤古镇"
},
{
"id":2,
"age":20,
"name":"l**i",
"email":"xu****@outlook.com",
"mobile":"139****5678",
"address":"西安市未央区************100米"
},
{
"id":8,
"age":30,
"name":"w****a",
"email":"wa****@163.com",
"mobile":"137****5678",
"address":"西安市未央区************100米"
}
]
5、表中原始数据
1 10 zhaoliu 450760999@qq.com 13722222222 宁波市慈溪市观海卫镇禹皇路999号鸣鹤古镇
2 20 lisi xu5555@outlook.com 13912345678 西安市未央区凤城二路与连心路交叉口南100米
8 30 wangba wangba@163.com 13712345678 西安市未央区凤城二路与连心路交叉口南100米
项目地址: mybatis-desensitization-plugin
声明: 公众号如需转载该篇文章,发表文章的头部一定要 告知是转至公众号: 后端元宇宙。同时也可以问本人要markdown原稿和原图片。其它情况一律禁止转载!
基于Mybatis插件方式实现数据脱敏处理的更多相关文章
- Spring Boot CRUD+分页(基于Mybatis注解方式)
步骤一:关于Mybatis Mybatis 是用来进行数据库操作的框架.其中分页使用Mybatis中的PageHelper插件. Mybatis与hibernate对比: 1.hibernate是一个 ...
- Mybatis 接口方式对数据的增删改查 一对一关联查询
数据库中有两个表 student 和studentInfo student表中的字段和数据 studentInfo表中的字段 ok数据库说完了,开始建立一个项目,对数据库中的数据进行操作吧 新建jav ...
- 获取mybatis注解方式新增数据时非自增插入的主键
场景:插入数据的时候,获取不到非自增的主键.原因:对象中没有主键的值,插入后主键才有值. 解决方案:使用 @SelectKey @SelectKey中: statement是要运行的SQL语句,即查询 ...
- MyBatis中批量插入数据对插入记录数的限制
<基于Mybatis框架的批量数据插入的性能问题的探讨>(作者:魏静敏 刘欢杰 来源:<计算机光盘软件与应用> 2013 年第 19 期)中提到批量插入的记录数不能超过1000 ...
- Mybatis框架基于注解的方式,实对数据现增删改查
编写Mybatis代码,与spring不一样,不需要导入插件,只需导入架包即可: 在lib下 导入mybatis架包:mybatis-3.1.1.jarmysql驱动架包:mysql-connecto ...
- Maven插件方式使用Mybatis Generator
Mybatis Generator Mybatis Generator简称MBG,可以根据数据库自动生成实体类.单表查询接口及其映射xml文件(也可以选择以注解方式生成). 下面介绍一下以maven插 ...
- 基于Mybatis分页插件PageHelper
基于Mybatis分页插件PageHelper 1.分页插件使用 1.POM依赖 PageHelper的依赖如下.需要新的版本可以去maven上自行选择 <!-- PageHelper 插件分页 ...
- 自己动手编写一个Mybatis插件:Mybatis脱敏插件
1. 前言 在日常开发中,身份证号.手机号.卡号.客户号等个人信息都需要进行数据脱敏.否则容易造成个人隐私泄露,客户资料泄露,给不法分子可乘之机.但是数据脱敏不是把敏感信息隐藏起来,而是看起来像真的一 ...
- mybatis通过插件方式实现读写分离
原理:通过自定义mybatis插件,拦截Executor的update和query方法,检查sql中有select就用读的库,其它的用写的库(如果有调用存储过程就另当别论了) @Intercepts( ...
随机推荐
- python黑帽子(第五章)
对开源CMS进行扫描 import os import queue import requests # 原书编写时间过于久远 现在有requests库对已经对原来的库进行封装 更容易调用 import ...
- QGIS 3.14插件开发——Win10系统PyCharm开发环境搭建四步走
前言:最近实习要求做一个QGIS插件,网上关于QGIS 3.14插件开发环境搭建的文档不多,而且也不算太全面.正好实习的时候写了一个文档,在这里给大家分享一下. 因为是Word转的Markdown,可 ...
- AQS源码阅读
简介 AQS 全程为 AbstractQueuedSynchronizer , 在 java.util.concurrent.locks包下的一个抽象类. 类的具体作用以及设计在开始类描述信息里面就有 ...
- 【多线程与高并发原理篇:3_java内存模型】
1. 概述 Java 内存模型即 Java Memory Model,简称 JMM.从抽象的角度来看,JMM 定义了线程和主内存之间的抽象关系,线程之间的共享变量存储在主内存中,每个线程都有一个私有的 ...
- WPF行为基础
理解行为 复杂的UI效果(缩放.拖拽.平滑等)通过样式与触发器比较难以实现,通过引入行为模型来实现.使用行为也可以处理UI操作之外的业务 程序集引用 System.Windows.Interactiv ...
- 跨域原因及SpringBoot、Nginx跨域配置
目录 概述 简单请求 跨域解决方案 概述 SpringBoot跨域配置 Nginx跨域配置 概述 MDN文档 Cross-Origin Resource Sharing (CORS) 跨域的英文是Cr ...
- 【kubevirt】VirtualMachineInstanceReplicaSet(vmis)-扩缩容-弹性伸缩
@ 目录 概述/理解 使用场景 创建vmis 扩缩容 弹性伸缩 方法1 方法2 概述/理解 VirtualMachineInstanceReplicaSet(vmis)确保指定数量的 VirtualM ...
- OAuth2密码模式已死,最先进的Spring Cloud认证授权方案在这里
旧的Spring Security OAuth2停止维护已经有一段时间了,99%的Spring Cloud微服务项目还在使用这些旧的体系,严重青黄不接.很多同学都在寻找新的解决方案,甚至还有念念不忘密 ...
- SQL表的创建
一,创建表 1.使用鼠标创建表 1,进入SQL进行连接 编辑 2,在左边会有一个对象资源管理器,右键数据库,在弹出的窗口中选择新建数据库 编辑 3,给这个包取个名字,在这个界面可以给这个表选 ...
- thusc2022游记
DAY -1: 刷往年相关的题 DAY 0: 刷会儿题了,搞电脑,下obs.不过,发现电脑出了很多问题. obs没有录频效果,因为卡,杀毒软件把vc++全都删了.因此无dll文件错误,搞了一晚上都没搞 ...