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

【数据脱敏】⭐️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> &lt;!&ndash; 替换为与你的Spring Boot兼容的版本 &ndash;&gt;--></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 实现隐私数据加密

目录 &#x1f378;前言 &#x1f37b;一、Jackson 序列化库 &#x1f37a;二、方案实践 2.1 环境准备 2.2 依赖引入 2.3 代码编写 &#x1f49e;️三、接口测试 &#x1f379;四、章末 &#x1f378;前言 小伙伴们大家好&#xff0c;最近也是很忙啊&#xff0c;上次的文章…...

骑砍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实例 创建产品 添加设备 本文首发于&#xff1a;【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&#xff0c;本文以Ubuntu20.04_x64&#xf…...

【漏洞复现】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之前版本存在代码问题漏洞&#xff0c;该漏洞源于存在服务器端请求伪造 (SSRF) 漏洞 0x03 搜索引擎 body"/_nex…...

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 小区小朋友统计(100分) - 三语言AC题解(Python/Java/Cpp)

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

Vuex看这一篇就够了

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

Kafka集群创建

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

2024.7.22 作业

1.将双向链表和循环链表自己实现一遍&#xff0c;至少要实现创建、增、删、改、查、销毁工作 循环链表 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中&#xff0c;要并发地执行多个HTTP请求&#xff0c;可以使用aiohttp这样的异步HTTP客户端库&#xff0c;因为它支持异步编程&#xff0c;能够显著提高IO密集型任务的性能&#xff0c;比如网络请求。requests-async并不是一个广泛认知的库&#xff08;虽然可能存在类似…...

Golang | Leetcode Golang题解之第257题二叉树的所有路径

题目&#xff1a; 题解&#xff1a; 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进行页面布局后&#xff0c;使用上下居中设置&#xff1a;align-item: center; 目标效果如下&#xff1a; 但是失效&#xff0c;不起作用&#xff0c;如下图所示&#xff1a; 各种排查过后发现设置了子模块 align-self 属性&#xff0c;这会覆盖容器上的 al…...

用Redisson写一个库存扣减的方法

使用Redisson来处理库存操作可以确保在高并发环境下库存数据的一致性和完整性。以下是使用Redisson实现库存管理的一些通用方法&#xff0c;包括获取库存、扣减库存、设置库存等。我们将使用Redisson的ReentrantLock来确保并发安全。 首先&#xff0c;确保你已经正确设置了Red…...

第2节课:文本内容与格式化——HTML中的文本处理技巧

目录 文本内容与格式化&#xff1a;段落和标题&#xff1a;构建文本基础段落 <p>标题 <h1> 到 <h6> 格式化&#xff1a;强调和样式加粗 <b>斜体 <i>下划线 <u> 列表&#xff1a;组织内容无序列表 <ul>有序列表 <ol>定义列表 &…...

temu平台电池/锂电池UN38.3资质合规解析

UN38.3资质合规解析 为满足相关法律法规和商品运输安全需求含锂电池商品需要提供对应的UN38.3资质。截至7月29日&#xff0c;相关类目下UN38.3资质待上传或上传失败的商品可能面临下架。 -01什么是UN38.3- 1&#xff09;UN38.3是指由联合国危险货物运输专家委员会编写的《试验…...

Huawei、Cisco 路由中 RIP 协议 summary 的用法

华为路由中 RIP summary summary用来使能 RIP 有类聚合&#xff0c;聚合后的路由以使用自然掩码的路由形式发布。undo summary用来取消有类聚合以便在子网之间进行路由&#xff0c;此时&#xff0c;子网的路由信息就会被发布出去。路由聚合降低了路由表中路由信息量。说明 有类…...

智能图像信息提取(飞桨OCR+ERNIE-Layout)

嘿&#xff0c;技术大佬们&#xff0c;今天我要分享的是一个超级棒的OCR技术方案&#xff0c;它结合了飞桨OCR和ERNIE-Layout&#xff0c;绝对是图像信息提取的利器&#xff01; 线上体验地址&#xff1a;智能图像信息提取(飞桨OCRERNIE-Layout) 它基于ERNIE -Layout和多版本Pa…...

Ubuntu 24.04 LTS Noble安装 FileZilla Server

FileZilla Server 是一款使用图形用户界面快速创建 FTP 服务器的软件。它有助于测试需要 FTP 服务器功能的各种项目。虽然早期的 FileZilla FTP 服务器仅适用于 Windows 和 macOS&#xff0c;但现在我们也可以在 Linux&#xff08;例如 Ubuntu 24.04&#xff09;上安装 FileZil…...

【关于使用swoole的知识点整理】

目录 &#xff08;1&#xff09;Swoole 如何理解&#xff0c;能解决你项目中的哪些痛点&#xff1f; &#xff08;2&#xff09;Swoole里的协程是什么&#xff0c;怎么用&#xff1f;为什么协程可以提高并发&#xff1f; &#xff08;3&#xff09;简述Swoole有哪些优点&…...

迁移学习:目标检测的加速器

迁移学习&#xff1a;目标检测的加速器 在深度学习领域&#xff0c;目标检测是一项至关重要的任务&#xff0c;广泛应用于从视频监控到自动驾驶等众多领域。然而&#xff0c;训练一个高性能的目标检测模型不仅需要大量的标注数据&#xff0c;还需要大量的计算资源和时间。迁移…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义&#xff08;Task Definition&…...

[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解

突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 ​安全措施依赖问题​ GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

工程地质软件市场:发展现状、趋势与策略建议

一、引言 在工程建设领域&#xff0c;准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具&#xff0c;正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

微信小程序云开发平台MySQL的连接方式

注&#xff1a;微信小程序云开发平台指的是腾讯云开发 先给结论&#xff1a;微信小程序云开发平台的MySQL&#xff0c;无法通过获取数据库连接信息的方式进行连接&#xff0c;连接只能通过云开发的SDK连接&#xff0c;具体要参考官方文档&#xff1a; 为什么&#xff1f; 因为…...

多种风格导航菜单 HTML 实现(附源码)

下面我将为您展示 6 种不同风格的导航菜单实现&#xff0c;每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

听写流程自动化实践,轻量级教育辅助

随着智能教育工具的发展&#xff0c;越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式&#xff0c;也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建&#xff0c;…...

AGain DB和倍数增益的关系

我在设置一款索尼CMOS芯片时&#xff0c;Again增益0db变化为6DB&#xff0c;画面的变化只有2倍DN的增益&#xff0c;比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析&#xff1a; 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...

如何应对敏捷转型中的团队阻力

应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中&#xff0c;明确沟通敏捷转型目的尤为关键&#xff0c;团队成员只有清晰理解转型背后的原因和利益&#xff0c;才能降低对变化的…...

AI语音助手的Python实现

引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...

在树莓派上添加音频输入设备的几种方法

在树莓派上添加音频输入设备可以通过以下步骤完成&#xff0c;具体方法取决于设备类型&#xff08;如USB麦克风、3.5mm接口麦克风或HDMI音频输入&#xff09;。以下是详细指南&#xff1a; 1. 连接音频输入设备 USB麦克风/声卡&#xff1a;直接插入树莓派的USB接口。3.5mm麦克…...