mybatis自制插件+注解实现数据脱敏

欢迎来到我的博客,代码的世界里,每一行都是一个故事


在这里插入图片描述

mybatis自制插件+注解实现数据脱敏

    • 前言
    • 数据脱敏的实现方式
    • 构思
      • 从哪个地方进行脱敏?
      • 它怎么知道我什么数据需要脱敏
    • 项目实现
      • 拦截器实现
      • 注解实现
      • 枚举实现
      • 效果图展示

前言

在数字时代,数据安全问题备受关注。想象一下,你的应用程序可能在处理各种敏感信息,例如用户的身份证号码、银行卡号等。如果这些信息泄露,后果不堪设想!但别担心,今天我们将揭开 MyBatis 数据脱敏的神秘面纱,让你的数据像戴着隐形护甲一样安全。

数据脱敏的实现方式

我认为数据脱敏主要可分为两种情况。首先,是在数据入库时进行脱敏处理,这意味着在存储之前就对敏感数据进行加密,比如可以使用类似于密码盐加密的方式进行加密。第二种情况是在从数据库查询出数据后进行脱敏处理。在这种情况下,脱敏的位置可以灵活选择,可以在查询结果立即脱敏,也可以在控制器层面进行脱敏处理。举例来说,可以利用AOP在方法执行后执行脱敏逻辑。这里我主要讲的是第二种中的查询结果立即脱敏。

构思

从哪个地方进行脱敏?

首先对于mybatis来说,它其实也是遵守像传统的JDBC操作的,只不过它在这其中点了几朵花。具体来说也就是下面的几步:

  1. Class.forName注册驱动
  2. 获取一个Connection对象
  3. 创建一个Statement对象
  4. execute()方法执行SQL语句,获取ResultSet结果集
  5. 通过ResultSet结果集给POJO的属性赋值
  6. 最后关闭相关的资源

通过上面的,我们就能知道我们需要拦截的位置了,也就是在ResultSet结果集那里,在mybatis中也就是org.apache.ibatis.executor.resultset.ResultSetHandler#handleResultSets方法

具体来说,ResultSetHandler 是 MyBatis 中的一个接口,它定义了数据库查询结果集处理的方法。其中,handleResultSets 方法用于处理从数据库返回的结果集。在 MyBatis 中,查询结果可以是单个对象、对象列表或映射,而 handleResultSets 方法则负责将这些查询结果转换为 Java 对象或集合。

它怎么知道我什么数据需要脱敏

在1的基础上我们需要明白,如何找到你标记为脱敏的数据,以及你如何标记脱敏。多想一步的话,我们就应该知道,我们脱敏的可能目前仅仅有手机号,身份证号,但是保不准以后就会有别的了,而且单纯的在拦截器中根据字段名称编码也不现实,于是就有了注解,比如对于user表中的phone我们需要脱敏,那么只需要在实体类的这个字段下加个注解即可

项目实现

这里我就不再过多的赘述了,直接贴代码

拦截器实现

package com.todoitbo.baseSpringbootDasmart.interceptor;

import com.todoitbo.baseSpringbootDasmart.annotation.Desensitize;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.plugin.*;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.sql.Statement;
import java.util.List;
import java.util.Properties;

/**
 * @author xiaobo
 */
@Intercepts({@Signature(
        type = ResultSetHandler.class,
        method = "handleResultSets",
        args = {Statement.class}
)})
@Component
public class DesensitizeInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 执行结果处理前的逻辑
        Object result = invocation.proceed();
        // 对结果进行脱敏处理
        if (result instanceof List) {
            List<?> list = (List<?>) result;
            for (Object obj : list) {
                desensitize(obj);
            }
        } else {
            desensitize(result);
        }
        return result;
    }

    private void desensitize(Object obj) {
        if (obj == null) {
            return;
        }
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            // 检查字段上是否存在Desensitize注解
            if (field.isAnnotationPresent(Desensitize.class)) {
                Desensitize desensitize = field.getAnnotation(Desensitize.class);
                try {
                    // 私有字段可以访问
                    field.setAccessible(true);
                    Object value = field.get(obj);
                    if (value instanceof String) {
                        // 字段脱敏
                        String desensitizedValue = desensitize.type().desensitize((String) value);
                        // 设置脱敏后的值
                        field.set(obj, desensitizedValue);
                    }
                } catch (IllegalAccessException e) {
                    // 处理异常
                }
            }
        }
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        // 可以通过配置文件传入参数
    }
}

注解实现

package com.todoitbo.baseSpringbootDasmart.annotation;

import com.todoitbo.baseSpringbootDasmart.Enum.DesensitizeType;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author xiaobo
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Desensitize {
    // 定义脱敏策略,可以扩展更多类型
    DesensitizeType type() default DesensitizeType.PHONE;
}

枚举实现

package com.todoitbo.baseSpringbootDasmart.Enum;

import java.util.function.Function;

/**
 * @author todoitbo
 * @date 2024/4/12
 */
// 脱敏策略枚举
public enum DesensitizeType {
    PHONE(s -> s.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")),
    EMAIL(s -> s.replaceAll("(\\w+)\\w{3}@(\\w+)", "$1***@$2"));
    // ...其他脱敏类型

    private final Function<String, String> desensitizer;

    DesensitizeType(Function<String, String> desensitizer) {
        this.desensitizer = desensitizer;
    }

    public String desensitize(String value) {
        return desensitizer.apply(value);
    }

    private String desensitizeValue(String value, DesensitizeType type) {
        return type.desensitize(value);
    }
    // 可以添加更多的脱敏类型
}

如果你追求特别完美,或者极致,你也可以优化上面的代码,具体从以下几点优化:

  1. 预编译正则表达式:
    • 每次调用desensitize方法时,都会创建一个新的正则表达式模式。
    • 预编译正则表达式,并将它们作为Pattern对象存储,可以减少正则表达式编译的开销。
  2. 减少lambda表达式创建的开销:
    • 每个枚举实例都会创建一个lambda表达式。
    • 可以考虑将脱敏逻辑移到一个静态方法中,并在枚举构造器里引用这个方法,减少lambda表达式的创建。
  3. 避免不必要的对象创建:
    • 如果传入的字符串不需要脱敏,或者已经是脱敏后的格式,可以直接返回原字符串,避免创建新的字符串对象。

效果图展示

image-20240412182811545

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/545189.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++初识

这里会对一些内容进行简单的提起&#xff0c;后面会详细讲解 一、注释 作用&#xff1a;在代码中加入一些说明和解释&#xff0c;方便自己或其他人阅读代码 两种格式&#xff1a; 1、单行注释&#xff1a; // 描述信息 通常放在一行代码的上方&#xff0c;或者一条语句的末…

LeetCode55题:跳跃游戏(原创)

【题目描述】 给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&am…

k8s网络详解

一、Kubernetes网络基础 1、kubernetes的网络层级 节点网络&#xff1a;集群宿主机节点间的网络通信&#xff0c;并且负责打通与集群外部的通讯。pod网络&#xff1a;为集群上的pod提供网络&#xff0c;通过CNI网络插件来完成&#xff0c;如Fannel、Calico、Cilium等。servic…

小米汽车值得去吗?最终拒了 offer。

车企选择 今天逛某职场 App 时&#xff0c;无意间看到一篇寻求 offer 抉择意见的帖子&#xff1a; 这位同学刚从加班闻名&#xff08;但 CEO 强调既学华为狼性&#xff0c;也学华为分配&#xff09;的理想汽车离职。 经过了 6 轮面试&#xff0c;收到了小米 offer&#xff0c;但…

【VTKExamples::Meshes】第十期 Decimation

很高兴在雪易的CSDN遇见你 VTK技术爱好者 QQ:870202403 公众号:VTK忠粉 前言 本文分享VTK样例Decimation,并解析接口vtkDecimatePro,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步! 你的点赞就是我的动力(^U^)ノ~YO…

[计算机效率] 时间记录工具:ManicTime

3.24 时间记录工具&#xff1a;ManicTime ManicTime是一款数据收集软件&#xff0c;主要用于记录电脑上各种软件使用所花费的时间以及电脑闲置的时间。用户还可以定制记录某一时间段内的系统活动。 数据收集&#xff1a;ManicTime能够静默运行于后台&#xff0c;自动跟踪并收…

如何检测和避免线程死锁?

在日常开发中涉及到多线程开发时候就很容易会产生死锁 what: 什么是线程死锁? 线程死锁是指两个或两个以上的线程在执行过程中&#xff0c;由于竞争资源或者由于彼此通信而造成的一种阻塞现象。当这些线程互相持有对方所需要的资源时&#xff0c;会互相等待对方释放资源&am…

ssm054班主任助理系统的设计与实现+jsp

班主任助理系统设计与实现 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本班主任助理系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间…

mybatis的一对多

业务&#xff1a;通常主表从表 查询&#xff0c;一对多关系&#xff0c;通常是先查主表&#xff0c;然后拿主表的 关联字段与从表关联。在代码中 通常用for 循环等方法给 从表的数据赋值&#xff0c;很麻烦&#xff0c;&#xff0c;&#xff0c;很麻烦。。。。 用mybatis的…

mac基础操作、快捷、软件快捷方式

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 mac基础操作、快捷、软件快捷方式 前言mac快捷操作快捷查找切换页面页面缩略访达和命令端切换创建文件夹创建文件删除文件/文件夹获取文件的路径移动文件或文件夹复制文件命令端常用命令 前言 主要是方…

Win11 使用 WSL2 安装 linux 子系统 ubuntu

Win11 使用 WSL2 安装 linux 子系统 ubuntu 段子手168 1、用 部署映像服务和管理工具 dism.exe 命令&#xff0c;开启 WSL2 按【WIN R】&#xff0c;打开【运行】&#xff0c;输入&#xff1a;【cmd】&#xff0c;管理员打开【命令行提示符】。 启用适用于 Linux 的 Windo…

小程序视频怎么保存到本地

掌握视频下载高手的妙招&#xff0c;轻松将微信小程序中的视频内容保存到本地&#x1f4e5;。遵循本文步骤&#xff0c;无需繁琐操作&#xff0c;快速实现视频下载&#xff0c;享受随时观看的便捷。 下载高手我已经打包好了 下载高手链接&#xff1a;https://pan.baidu.com/s…

#381. 四边形继承练习

太爽了 甚至还现学了叉积判断线段是否相交和求面积的方法 先给出我的代码&#xff1a; #include <iostream> #include <vector> #include <iomanip> #include <cmath>using namespace std;//下面需要补充多个类的声明及实现代码 const double EPS 1…

儿童护眼台灯怎么选?五款必选的高口碑护眼台灯推荐

儿童台灯&#xff0c;想必大家都不会陌生了&#xff0c;是一种学生频繁使用的小灯具&#xff0c;一般指放在桌面用的有底座的电灯。随着近年来儿童青少年的视力急速下滑&#xff0c;很多家长都会选择给孩子选择一款合适的护眼台灯&#xff0c;以便孩子夜晚学习能有个好的照明环…

数据结构—顺序表实现通讯录

在上一节我们基本了解了顺序表的基本知识&#xff0c;接下来我们就用顺序表来实现一下通讯录。 一、基于动态顺序表实现通讯录 1.1 功能介绍 1. 能够保存用户信息&#xff1a;姓名&#xff0c;性别&#xff0c;年龄&#xff0c;电话&#xff0c;地址等 2. 添加联系人信息 3. …

零基础使用FlexLua打造LoRa无线气体流量计,硬件轻松快速开发。

在工业领域&#xff0c;对气体流量进行准确监测和管理是保障生产安全和提高效率的重要环节。而LoRa&#xff08;长距离低功耗无线技术&#xff09;作为一种适用于远距离、低功耗的通信技术&#xff0c;为无线传感器网络的建设提供了可靠的解决方案。结合气体流量传感技术&#…

【JS】querySelectorAll和getElementsByClassName

现有一段代码&#xff0c;li的类名均为item&#xff0c;有一按钮可动态添加类名为item的li。 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge…

vue表格操作列,按钮太多显示... 点击后悬浮显示全部按钮

效果: 分析原理: 一共就三步,仔细看看很简单,位置要加对,代码结构下边有demo 代码结构demo: <el-table-columnlabel"操作"align"center"fixed"right"show-overflow-tooltip><template slot-scope"scope"><el-buttonsi…

润乾报表平台 InputServlet 任意文件读取漏洞复现

0x01 产品简介 润乾报表是一个纯JAVA的企业级报表工具&#xff0c;支持对J2EE系统的嵌入式部署&#xff0c;无缝集成。服务器端支持各种常见的操作系统&#xff0c;支持各种常见的关系数据库和各类J2 EE的应用服务器&#xff0c;客户端采用标准纯html方式展现&#xff0c;支持…

1000BASE-SX VS 1000BASE-LX SFP光模块

SFP光模块是一种小型可插拔光模块&#xff0c;用于支持1G速率的光纤通信&#xff0c;有多种不同类型。市场上使用较广泛是1000BASE-SX和1000BASE-LX SFP光模块。在本文中&#xff0c;飞速&#xff08;FS&#xff09;将对这两种LC SFP光模块进行简要介绍。 什么是1000BASE-SX S…