【数据脱敏】⭐️SpringBoot 整合 Jackson 实现隐私数据加密
目录
🍸前言
🍻一、Jackson 序列化库
🍺二、方案实践
2.1 环境准备
2.2 依赖引入
2.3 代码编写
💞️三、接口测试
🍹四、章末
🍸前言
小伙伴们大家好,最近也是很忙啊,上次的文章分享了 Caffeine 本地缓存,文章链接如下:
【Caffeine】⭐️SpringBoot 项目整合 Caffeine 实现本地缓存_springboot caffeine-CSDN博客
最近在别的技术分享上看到了数据脱敏的介绍,感觉平时接触的挺多的,比如个人私密信息在页面上显示的时候需要对部分信息加密,就像手机号中间几个位置用 “*” 代替(如下图),具体的实现也有很多方式,比如单独某一个接口需要加密,那么可以在接口返回值时处理下数据即可,但是如果过多的接口有此需求,挨个处理显然费时费力并且增加代码冗余,这个时候就可以选用全局处理的解决方案,实现一次编写,到处实现,具体的方案就是可以在序列化时处理数据 ,序列化工具常用的 Jackson 日常接触也很多
🍻一、Jackson 序列化库
Jackson 是一个流行的 Java 序列化/反序列化库,专门用于处理 JSON 数据。它提供了一组功能强大且灵活的 API,可以帮助开发者在 Java 对象和 JSON 数据之间进行转换。有以下几个特性,灵活、高效、应用广泛(整合各种框架),比如我们经常接触的 web 系统,就是将后端的数据 Json 序列化后传递给前端实现的
🍺二、方案实践
2.1 环境准备
测试项目是基于 SpringBoot 框架的项目实现,另外接口测试使用 Apipost 实现模拟请求
2.2 依赖引入
因为使用的 SpringBoot 框架,所以在创建项目的时候就已经勾选了 web 模块,而这些模块已经集成了相关的 Jackson 包,依赖如下
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
如果项目中没有的话,也可以手动引入,依赖如下:
注:手动引入的时候,需要注意下版本问题,项目启动的时候可能会遇到如下情况,这种情况我在博客上搜索了相关的文章,有讲解的不是很多,但是可行的一种方案就是自己不要指定版本,使用父依赖的即可解决
Error starting Tomcat context. Exception: org.springframework.beans.factory.BeanCreationException. Message: Error creating bean with name 'formContentFilter' defined in class path resource
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId>
<!-- <version>2.9.8</version>--></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId>
<!-- <version>2.9.8</version>--></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId>
<!-- <version>2.9.8</version>--></dependency><dependency><groupId>com.fasterxml.jackson.datatype</groupId><artifactId>jackson-datatype-jsr310</artifactId>
<!-- <version>2.13.0</version> <!– 替换为与你的Spring Boot兼容的版本 –>--></dependency>
2.3 代码编写
2.3.1 脱敏数据类型枚举
指定哪些类型的数据需要脱敏,命名为枚举类,方便后续调用
/*** @author HuangBen */
public enum SensitiveEnum {/*** 中文名*/CHINESE_NAME,/*** 身份证号*/ID_CARD,/*** 手机号*/MOBILE_PHONE,/*** 地址*/ADDRESS,/*** 电子邮件*/EMAIL,/*** 银行卡*/BANK_CARD,
}
2.3.2 处理隐私数据工具类
这里将已有的处理工具封装为一个工具类,方便设置参数以及调用,这里导入的工具类如果报错,说明并没有引入依赖,依赖如下:
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.12.0</version></dependency>
import org.apache.commons.lang3.StringUtils;/*** @author HuangBen */
public class SensitiveInfoUtils {/*** [中文姓名] 只显示第一个汉字,其他隐藏为2个星号<例子:李**>*/public static String chineseName(final String fullName) {if (StringUtils.isBlank(fullName)) {return "";}final String name = StringUtils.left(fullName, 1);return StringUtils.rightPad(name, StringUtils.length(fullName), "*");}/*** [中文姓名] 只显示第一个汉字,其他隐藏为2个星号<例子:李**>*/public static String chineseName(final String familyName, final String givenName) {if (StringUtils.isBlank(familyName) || StringUtils.isBlank(givenName)) {return "";}return chineseName(familyName + givenName);}/*** [身份证号] 显示最后四位,其他隐藏。共计18位或者15位。<例子:420**********5762>*/public static String idCardNum(final String id) {if (StringUtils.isBlank(id)) {return "";}return StringUtils.left(id, 3).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(id, 4), StringUtils.length(id), "*"),"***"));}/*** [手机号码] 前三位,后四位,其他隐藏<例子:138******1234>*/public static String mobilePhone(final String num) {if (StringUtils.isBlank(num)) {return "";}return StringUtils.left(num, 3).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(num, 4), StringUtils.length(num), "*"),"***"));}/*** [地址] 只显示到地区,不显示详细地址;我们要对个人信息增强保护<例子:北京市海淀区****>** @param sensitiveSize 敏感信息长度*/public static String address(final String address, final int sensitiveSize) {if (StringUtils.isBlank(address)) {return "";}final int length = StringUtils.length(address);return StringUtils.rightPad(StringUtils.left(address, length - sensitiveSize), length, "*");}/*** [电子邮箱] 邮箱前缀仅显示第一个字母,前缀其他隐藏,用星号代替,@及后面的地址显示<例子:g**@163.com>*/public static String email(final String email) {if (StringUtils.isBlank(email)) {return "";}final int index = StringUtils.indexOf(email, "@");if (index <= 1) {return email;} else {return StringUtils.rightPad(StringUtils.left(email, 1), index, "*").concat(StringUtils.mid(email, index, StringUtils.length(email)));}}/*** [银行卡号] 前六位,后四位,其他用星号隐藏每位1个星号<例子:6222600**********1234>*/public static String bankCard(final String cardNum) {if (StringUtils.isBlank(cardNum)) {return "";}return StringUtils.left(cardNum, 6).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(cardNum, 4), StringUtils.length(cardNum), "*"),"******"));}}
2.3.3 编写脱敏序列化实现类
这里就是先用刚才工具类处理数据再进行序列化
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import java.io.IOException;
import java.util.Objects;/*** @author HuangBen*/
public class SensitiveSerialize extends JsonSerializer<String> implements ContextualSerializer {/*** 脱敏类型*/private SensitiveEnum type;@Overridepublic void serialize(String s, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {switch (this.type) {case CHINESE_NAME: {jsonGenerator.writeString(SensitiveInfoUtils.chineseName(s));break;}case ID_CARD: {jsonGenerator.writeString(SensitiveInfoUtils.idCardNum(s));break;}case MOBILE_PHONE: {jsonGenerator.writeString(SensitiveInfoUtils.mobilePhone(s));break;}case ADDRESS: {jsonGenerator.writeString(SensitiveInfoUtils.address(s, 4));break;}case EMAIL: {jsonGenerator.writeString(SensitiveInfoUtils.email(s));break;}case BANK_CARD: {jsonGenerator.writeString(SensitiveInfoUtils.bankCard(s));break;}}}@Overridepublic JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {// 为空直接跳过if (beanProperty != null) {// 非 String 类直接跳过if (Objects.equals(beanProperty.getType().getRawClass(), String.class)) {SensitiveWrapped sensitiveWrapped = beanProperty.getAnnotation(SensitiveWrapped.class);if (sensitiveWrapped == null) {sensitiveWrapped = beanProperty.getContextAnnotation(SensitiveWrapped.class);}if (sensitiveWrapped != null) {// 如果能得到注解,就将注解的 value 传入 SensitiveSerializereturn new SensitiveSerialize(sensitiveWrapped.value());}}return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);}return serializerProvider.findNullValueSerializer(beanProperty);}public SensitiveSerialize() {}public SensitiveSerialize(final SensitiveEnum type) {this.type = type;}
}
2.3.4 编写脱敏注解类
通过此注解可以灵活标注哪些数据需要脱敏处理,并且标注对应的枚举类型;注意这里指定了序列化的实现类为我们自己刚定义的,具体实现的功能就是遇到此注解标注的字段,序列化的时候使用我们指定的序列化器,我们自定义的序列化器中对每种类型的字段都有相应的处理逻辑
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;/*** @author HuangBen */
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = SensitiveSerialize.class)
public @interface SensitiveWrapped {/*** 脱敏类型* @return*/SensitiveEnum value();
}
2.3.5 编写测试实体类
这里指定了 mobile , idcard 两个字段需要脱敏,并且指明了按照哪一种数据类型脱敏处理
import lombok.Data;/*** @author HuangBen */
@Data
public class UserEntity {/*** 用户ID*/private Long userId;/*** 用户姓名*/private String name;/*** 手机号*/@SensitiveWrapped(SensitiveEnum.MOBILE_PHONE)private String mobile;/*** 身份证号码*/@SensitiveWrapped(SensitiveEnum.ID_CARD)private String idCard;/*** 年龄*/private String sex;/*** 性别*/private int age;}
💞️三、接口测试
简单用一个 restful 接口测试下处理后的数据是否脱敏,接口如下:
利用接口请求工具,确实按照我们指定的字段以及类型进行脱敏处理了,测试成功,结果如下:
🍹四、章末
通过这种方式实现的数据脱敏处理,后续在使用的时候也很方便,有哪些需要处理的字段只需要在实体类的字段上方添加注解并且指定脱敏类型即可,符合开闭原则,并且遵循很少改动原有代码的规则;
文章到这里就结束了~
相关文章:

【数据脱敏】⭐️SpringBoot 整合 Jackson 实现隐私数据加密
目录 🍸前言 🍻一、Jackson 序列化库 🍺二、方案实践 2.1 环境准备 2.2 依赖引入 2.3 代码编写 💞️三、接口测试 🍹四、章末 🍸前言 小伙伴们大家好,最近也是很忙啊,上次的文章…...

骑砍2霸主MOD开发(18)-多人联机模式开发环境搭建
一.多人联机模式网络拓扑图 二.专用服务器搭建(DedicatedServer) <1.Token生成(用于LobbyServer的校验): 进入多人联机大厅,ALT~打开RGL控制台,输入customserver.gettoken Token文件路径:C:\Users\taohu\Documents\Mount and Blade II Bannerlord\Tokens <2.启动专用服务…...

【HZHY-AI300G智能盒试用连载体验】在华为IoTDA平台上建立设备
目录 华为IoTDA平台 注册IoTDA实例 创建产品 添加设备 本文首发于:【HZHY-AI300G智能盒试用连载体验】 智能工业互联网网关 - 北京合众恒跃科技有限公司 - 电子技术论坛 - 广受欢迎的专业电子论坛! 在上一篇博文中介绍了如何在HZHY-AI300G智能盒创建南向设备&a…...

【LLM】-05-提示工程-部署Langchain-Chat
目录 1、软硬件要求 1.1、软件要求 1.2、硬件要求 1.3、个人配置参考 2、创建cuda环境 3、下载源码及模型 4、配置文件修改 5、初始化知识库 5.1、训练自己的知识库 6、启动 7、API接口调用 7.1、使用openai 参考官方wiki,本文以Ubuntu20.04_x64…...

【漏洞复现】Next.js框架存在SSRF漏洞(CVE-2024-34351)
0x01 产品简介 ZEIT Next.js是ZEIT公司的一款基于Vue.js、Node.js、Webpack和Babel.js的开源Web应用框架。 0x02 漏洞概述 ZEIT Next.js 13.4版本至14.1.1之前版本存在代码问题漏洞,该漏洞源于存在服务器端请求伪造 (SSRF) 漏洞 0x03 搜索引擎 body"/_nex…...

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 小区小朋友统计(100分) - 三语言AC题解(Python/Java/Cpp)
🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,支持题目在线…...

Vuex看这一篇就够了
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 非常期待和您一起在这个小…...

Kafka集群创建
这样就创建好了docker4个镜像,三个node,一个manager。 其中,浏览器访问的是manager对应的那个url,直接在里面加Cluster...

2024.7.22 作业
1.将双向链表和循环链表自己实现一遍,至少要实现创建、增、删、改、查、销毁工作 循环链表 looplinklist.h #ifndef LOOPLINKLIST_H #define LOOPLINKLIST_H#include <myhead.h>typedef int datatype;typedef struct Node {union {int len;datatype data;}…...
如何使用aiohttp或requests-async等库并发地执行多个HTTP请求
在Python中,要并发地执行多个HTTP请求,可以使用aiohttp这样的异步HTTP客户端库,因为它支持异步编程,能够显著提高IO密集型任务的性能,比如网络请求。requests-async并不是一个广泛认知的库(虽然可能存在类似…...

Golang | Leetcode Golang题解之第257题二叉树的所有路径
题目: 题解: func binaryTreePaths(root *TreeNode) []string {paths : []string{}if root nil {return paths}nodeQueue : []*TreeNode{}pathQueue : []string{}nodeQueue append(nodeQueue, root)pathQueue append(pathQueue, strconv.Itoa(root.V…...

关于css中flex布局垂直居中失效问题的原因
项目中遇到用flex进行页面布局后,使用上下居中设置:align-item: center; 目标效果如下: 但是失效,不起作用,如下图所示: 各种排查过后发现设置了子模块 align-self 属性,这会覆盖容器上的 al…...
用Redisson写一个库存扣减的方法
使用Redisson来处理库存操作可以确保在高并发环境下库存数据的一致性和完整性。以下是使用Redisson实现库存管理的一些通用方法,包括获取库存、扣减库存、设置库存等。我们将使用Redisson的ReentrantLock来确保并发安全。 首先,确保你已经正确设置了Red…...
第2节课:文本内容与格式化——HTML中的文本处理技巧
目录 文本内容与格式化:段落和标题:构建文本基础段落 <p>标题 <h1> 到 <h6> 格式化:强调和样式加粗 <b>斜体 <i>下划线 <u> 列表:组织内容无序列表 <ul>有序列表 <ol>定义列表 &…...

temu平台电池/锂电池UN38.3资质合规解析
UN38.3资质合规解析 为满足相关法律法规和商品运输安全需求含锂电池商品需要提供对应的UN38.3资质。截至7月29日,相关类目下UN38.3资质待上传或上传失败的商品可能面临下架。 -01什么是UN38.3- 1)UN38.3是指由联合国危险货物运输专家委员会编写的《试验…...
Huawei、Cisco 路由中 RIP 协议 summary 的用法
华为路由中 RIP summary summary用来使能 RIP 有类聚合,聚合后的路由以使用自然掩码的路由形式发布。undo summary用来取消有类聚合以便在子网之间进行路由,此时,子网的路由信息就会被发布出去。路由聚合降低了路由表中路由信息量。说明 有类…...
智能图像信息提取(飞桨OCR+ERNIE-Layout)
嘿,技术大佬们,今天我要分享的是一个超级棒的OCR技术方案,它结合了飞桨OCR和ERNIE-Layout,绝对是图像信息提取的利器! 线上体验地址:智能图像信息提取(飞桨OCRERNIE-Layout) 它基于ERNIE -Layout和多版本Pa…...

Ubuntu 24.04 LTS Noble安装 FileZilla Server
FileZilla Server 是一款使用图形用户界面快速创建 FTP 服务器的软件。它有助于测试需要 FTP 服务器功能的各种项目。虽然早期的 FileZilla FTP 服务器仅适用于 Windows 和 macOS,但现在我们也可以在 Linux(例如 Ubuntu 24.04)上安装 FileZil…...
【关于使用swoole的知识点整理】
目录 (1)Swoole 如何理解,能解决你项目中的哪些痛点? (2)Swoole里的协程是什么,怎么用?为什么协程可以提高并发? (3)简述Swoole有哪些优点&…...
迁移学习:目标检测的加速器
迁移学习:目标检测的加速器 在深度学习领域,目标检测是一项至关重要的任务,广泛应用于从视频监控到自动驾驶等众多领域。然而,训练一个高性能的目标检测模型不仅需要大量的标注数据,还需要大量的计算资源和时间。迁移…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

Keil 中设置 STM32 Flash 和 RAM 地址详解
文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...

C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...

HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...