SpringBoot中优雅的实现隐私数据脱敏(提供Gitee源码)

前言:在实际项目开发中,可能会对一些用户的隐私信息进行脱敏操作,传统的方式很多都是用replace方法进行手动替换,这样会由很多冗余的代码并且后续也不好维护,本期就讲解一下如何在SpringBoot中优雅的通过序列化的方式去实现数据的脱敏操作!

目录

一、导入pom依赖

二、DesensitizationEnum枚举类

三、Desensitization自定义注解

四、DesensitizationSerialize脱敏序列化器

五、User实体类

六、UserController请求层

七、运行测试

八、Gitee源码

九、总结


一、导入pom依赖

完整代码:

    <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.18</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>

二、DesensitizationEnum枚举类

在DesensitizationSerialize序列化类中,会根据脱敏注解的type值,也就是DesensitizationEnum 中的类型,来判断需要使用哪种脱敏方式。

这边我就简单定义了5个枚举类型:

完整代码:

package com.example.desensitization.constant;public enum DesensitizationEnum {/*** 自定义*/CUSTOM_RULE,/*** 身份证号码*/ID_CARD_NO,/*** 电话号码*/PHONE,/*** 地址*/ADDRESS,/*** 银行卡号*/BANK_CARD_NO,
}

三、Desensitization自定义注解

这个是自定义的注解@Desensitization,用于标注需要进行脱敏的字段。

主要包含以下元注解和属性

1、@Target(ElementType.FIELD):表示该注解只能用于字段上。

2、@Retention(RetentionPolicy.RUNTIME):表示该注解可以保留到运行时。

3、@JacksonAnnotationsInside:是一个Jackson的元注解,表示该注解可以作为Json序列化的注解。

4、@JsonSerialize:标注使用DesensitizationSerialize来进行序列化。

5、DesensitizationEnum type:需要脱敏的类型,对应枚举中的脱敏类型。

6、int start/end:可选的起始位置和结束位置,对于脱敏类型为字符串时有效。

完整代码:

package com.example.desensitization.annotation;import com.example.desensitization.constant.DesensitizationEnum;
import com.example.desensitization.serialize.DesensitizationSerialize;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = DesensitizationSerialize.class)
public @interface Desensitization {DesensitizationEnum type();int start() default 0;int end() default 0;}

四、DesensitizationSerialize脱敏序列化器

1、继承JsonSerializer<String>JsonSerializer是Jackson的序列化器基类,实现了将对象序列化为JSON的核心方法,这里继承它是为了实现字符串的自定义序列化。

2、实现ContextualSerializer接口ContextualSerializer可以让序列化器基于上下文环境进行定制化,实现这个接口后,可以实现createContextual()方法。

关键代码:

@AllArgsConstructor
@NoArgsConstructor
public class DesensitizationSerialize extends JsonSerializer<String> implements ContextualSerializer {private DesensitizationEnum type;private Integer start;private Integer end;
}

自定义序列化器方式可以实现非侵入式的灵活脱敏,对业务代码零侵入,且不依赖Spring等框架,更适合编写独立的应用服务。当然,AOP实现也有其适用场景,可以作为另一种可选方案。

createContextual()方法:

1、Controller的user()方法被调用,构建并返回了一个User对象。

2、开始对User对象进行JSON序列化,会先调用我们定义的DesensitizationSerialize中createContextual()方法,如果这个实体类被createContextual()方法处理过,则以后不会再走该方法,直接走serialize()方法。

3、DesensitizationSerialize会检查当前类字段是否有@Desensitization注解,如果有N个,则根据注解的type、start和end参数创建N个DesensitizationSerialize实例。

关键代码:

@Overridepublic JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty)throws JsonMappingException {if (beanProperty != null) {// 获取当前正在处理的字段的类型,判断如果是 String 类型则进行后续脱敏逻辑处理if (Objects.equals(beanProperty.getType().getRawClass(), String.class)) {// 通过 beanProperty 获取在字段上标注的 @Desensitization 注解Desensitization desensitization = beanProperty.getAnnotation(Desensitization.class);// 如果没有就尝试获取类注解if (desensitization == null) {desensitization = beanProperty.getContextAnnotation(Desensitization.class);}// 不为nullif (desensitization != null) {// 如果获取到了注解,则根据注解的 type、start 和 end 参数创建 DesensitizationSerialize 实例,这是脱敏处理的序列化器return new DesensitizationSerialize(desensitization.type(), desensitization.start(),desensitization.end());}}// 直接返回默认的序列化器return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);}// 直接返回默认的序列化器return serializerProvider.findNullValueSerializer(null);}

serialize方法: 

JsonGenerator是Jackjson提供的JSON生成器类。在自定义序列化器的serialize()方法中,会传入JsonGenerator实例。serialize()方法需要通过JsonGenerator将脱敏后的字符串写入到结果JSON中。

CharSequenceUtil和DesensitizedUtil都是hutool提供的工具类。

整体流程是:

1、根据注解的参数动态选择脱敏策略。

2、调用对应 Hutool 的脱敏函数处理字符串。

3、将脱敏结果写入JSON。

关键代码:

    @Overridepublic void serialize(String s, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)throws IOException {switch (type){//自定义case CUSTOM_RULE:jsonGenerator.writeString(CharSequenceUtil.hide(s, start, end));break;//身份证case ID_CARD_NO:jsonGenerator.writeString(DesensitizedUtil.idCardNum(s, 2, 6));break;//手机号case PHONE:jsonGenerator.writeString(DesensitizedUtil.mobilePhone(s));break;//地址case ADDRESS:jsonGenerator.writeString(DesensitizedUtil.address(s, 2));break;// 银行卡脱敏case BANK_CARD_NO:jsonGenerator.writeString(DesensitizedUtil.bankCard(s));break;default:}}

综上,整体的执行逻辑如下:

1、Controller返回一个实体对象。

2、如果实体对象是第一次进行脱敏,则会调用createContextual()方法。

3、获取当前实体对象所有使用Desensitization注解的字符串字段,创建对应的DesensitizationSerialize实例,实现脱敏处理的序列化器。

4、执行serialize()方法中switch的处理逻辑,由JsonGenerator将脱敏后的字符串写入到结果JSON中。

5、返回Json数据。

完整代码:

package com.example.desensitization.serialize;import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.DesensitizedUtil;
import com.example.desensitization.annotation.Desensitization;
import com.example.desensitization.constant.DesensitizationEnum;
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 lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import java.io.IOException;
import java.util.Objects;@AllArgsConstructor
@NoArgsConstructor
public class DesensitizationSerialize extends JsonSerializer<String> implements ContextualSerializer {private DesensitizationEnum type;private Integer start;private Integer end;@Overridepublic void serialize(String s, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)throws IOException {switch (type){//自定义case CUSTOM_RULE:jsonGenerator.writeString(CharSequenceUtil.hide(s, start, end));break;//身份证case ID_CARD_NO:jsonGenerator.writeString(DesensitizedUtil.idCardNum(s, 2, 6));break;//手机号case PHONE:jsonGenerator.writeString(DesensitizedUtil.mobilePhone(s));break;//地址case ADDRESS:jsonGenerator.writeString(DesensitizedUtil.address(s, 2));break;// 银行卡脱敏case BANK_CARD_NO:jsonGenerator.writeString(DesensitizedUtil.bankCard(s));break;default:}}@Overridepublic JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty)throws JsonMappingException {if (beanProperty != null) {// 获取当前正在处理的字段的类型,判断如果是 String 类型则进行后续脱敏逻辑处理if (Objects.equals(beanProperty.getType().getRawClass(), String.class)) {// 通过 beanProperty 获取在字段上标注的 @Desensitization 注解Desensitization desensitization = beanProperty.getAnnotation(Desensitization.class);// 如果没有就尝试获取类注解if (desensitization == null) {desensitization = beanProperty.getContextAnnotation(Desensitization.class);}// 不为nullif (desensitization != null) {// 如果获取到了注解,则根据注解的 type、start 和 end 参数创建 DesensitizationSerialize 实例,这是脱敏处理的序列化器return new DesensitizationSerialize(desensitization.type(), desensitization.start(),desensitization.end());}}// 直接返回默认的序列化器return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);}// 直接返回默认的序列化器return serializerProvider.findNullValueSerializer(null);}
}

五、User实体类

给想要脱敏的字段加上 @Desensitization(type = DesensitizationEnum.枚举类型)注解即可。

完整代码:

package com.example.desensitization.domain;import com.example.desensitization.annotation.Desensitization;
import com.example.desensitization.constant.DesensitizationEnum;
import lombok.Builder;
import lombok.Data;@Data
@Builder
public class User {/*** 主键*/private String id;/*** 用户名*/private String name;/*** 身份证号码*/@Desensitization(type = DesensitizationEnum.ID_CARD_NO)private String idCardNo;/*** 电话号码*/@Desensitization(type = DesensitizationEnum.PHONE)private String phone;/*** 地址*/@Desensitization(type = DesensitizationEnum.CUSTOM_RULE,start = 2,end = 5)private String address;/*** 银行卡号*/@Desensitization(type = DesensitizationEnum.BANK_CARD_NO)private String bankCardNo;}

六、UserController请求层

完整代码:

package com.example.desensitization.controller;import com.example.desensitization.domain.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.UUID;@RestController
@RequestMapping
public class UserController {@GetMapping("/user")public User user(){User user = User.builder().id(UUID.randomUUID().toString()).name("张三").idCardNo("32089809285012823").phone("13919819285").bankCardNo("62427292012731238812").address("江苏省南通市").build();return user;}}

七、运行测试

浏览器直接访问:http://localhost:8080/user

可以看到隐私的信息都进行了数据脱敏的处理!

八、Gitee源码

源码地址:SpringBoot中优雅的实现隐私数据脱敏

九、总结

以上就是我对于SpringBoot中如何优雅的实现隐私数据脱敏的完整教程,如有问题,欢迎评论区留言! 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

设计模式之备忘录模式(Memento)的C++实现

1、备忘录模式的提出 在软件功能开发过程中&#xff0c;某些对象的状态在转换过程中&#xff0c;由于业务场景需要&#xff0c;要求对象能够回溯到对象之前某个点的状态。如果使用一些共有接口来让其他对象得到对象的状态&#xff0c;便会暴露对象的实现细节。备忘录模式是在不…

【学会动态规划】单词拆分(24)

目录 动态规划怎么学&#xff1f; 1. 题目解析 2. 算法原理 1. 状态表示 2. 状态转移方程 3. 初始化 4. 填表顺序 5. 返回值 3. 代码编写 写在最后&#xff1a; 动态规划怎么学&#xff1f; 学习一个算法没有捷径&#xff0c;更何况是学习动态规划&#xff0c; 跟我…

【模拟集成电路】反馈系统——基础到进阶(一)

【模拟集成电路】反馈系统——基础到进阶 前言1 概述2 反馈电路特性2.1增益灵敏度降低2.2 终端阻抗变化2.3 带宽拓展2.4 非线性减小 3 放大器分类4 反馈检测和返回机制4.1 按照检测物理量分类4.2 按照检测拓扑连接分类 5 反馈结构分析6 二端口方法7 波特方法6 麦德布鲁克方法 前…

VS2015打开Qt的pro项目文件 报错

QT报错&#xff1a;Project ERROR: msvc-version.conf loaded but QMAKE_MSC_VER isn‘t set 解决方法&#xff1a; 找到本机安装的QT路径&#xff0c;找到“msvc-version.conf”文件&#xff0c;用记事本打开&#xff0c; 在其中添加版本“QMAKE_MSC_VER 1900”保存即可。 …

CSS:filter滤镜 详解(用法 + 代码 + 例子 + 效果)

文章目录 filter 滤镜blur() 模糊度例子 渐变光晕 brightness() 元素亮度contrast() 对比度grayscale() 元素灰度hue-rorate() 色相opacity() 透明度invert() 反转颜色saturate() 饱和度 backdrop-filter 蒙版&#xff0c;滤镜例子 卷轴展开 filter 滤镜 动图为效果添加前后对…

界面组件Telerik UI for WinForms R2 2023——拥有VS2022暗黑主题

Telerik UI for WinForms拥有适用Windows Forms的110多个令人惊叹的UI控件。所有的UI for WinForms控件都具有完整的主题支持&#xff0c;可以轻松地帮助开发人员在桌面和平板电脑应用程序提供一致美观的下一代用户体验。 Telerik UI for WinForms R2 2023于今年6月份发布&…

Blender 混合现实3D模型制作指南【XR】

本教程分步展示如何&#xff1a; 减少 3D 模型的多边形数量&#xff0c;使其满足 Microsoft Dynamics 365 Guides 和使用 Microsoft Power Apps 创建的应用程序中包含的混合现实组件的特定性能目标的性能需求。将 3D 模型的多种材质&#xff08;颜色&#xff09;组合成可应用于…

​Kubernetes的演变:从etcd到分布式SQL的过渡

DevRel领域专家Denis Magda表示&#xff0c;他偶然发现了一篇解释如何用PostgreSQL无缝替换etcd的文章。该文章指出&#xff0c;Kine项目作为外部etcd端点&#xff0c;可以将Kubernetes etcd请求转换为底层关系数据库的SQL查询。 受到这种方法的启发&#xff0c;Magda决定进一步…

求Win11系统virtualbox+vagrant安装MacOS虚拟机

文章目录 一、背景二、素材2.1、virtualboxvagrant 三、问题3.1、安装失败3.2、第二个失败3.3、网络说 四、求助 一、背景 题主&#xff0c;主要是穷&#xff0c;没钱买mac笔记本或相关系统的苹果产品&#xff0c;哈哈&#xff0c;偶尔也有用过MacOS系统&#xff0c;只是还没有…

actuator/prometheus使用pushgateway上传jvm监控数据

场景 准备 prometheus已经部署pushgateway服务&#xff0c;访问{pushgateway.server:9091}可以看到面板 实现 基于springboot引入支持组件&#xff0c;版本可以 <!--监控检查--><dependency><groupId>org.springframework.boot</groupId><artifa…

H3C交换机如何配置本地端口镜像并在PC上使用Wireshake抓包

环境: H3C S6520-26Q-SI version 7.1.070, Release 6326 Win 10 专业版 Wireshake Version 4.0.3 问题描述: H3C交换机如何配置本地端口镜像并在PC上使用Wireshake抓包 解决方案: 配置交换机本地端口镜像 1.进入系统视图,并创建本地镜像组1 <H3C>system-vie…

高效反编译luac文件

对于游戏开发人员,有时候希望从一些游戏apk中反编译出源代码,进行学习,但是如果你触碰到法律边缘,那么你要非常小心。 这篇文章,我针对一些用lua写客户端或者服务器的编译过的luac文件进行反编译,获取其源代码的过程。 这里我不赘述如何反编译解压apk包的过程了,只说重点…

【【STM32之GPIO】】

STM32之GPIO 学完了正点原子自带的视频课之后感觉仍然一知半解现在更新一下来自其他版本的STM32学习 GPIO 就是 General Purpose Input Output 中文名叫通用输入输出口 可配置8种输入输出模式 引脚电平 0V~3.3V 部分引脚可容忍5V 输出模式下可控制端口输出高低电平&#xff…

grafana-zabbix基础操作篇------导入数据源

文章目录 一、grafana的安装1.1、下载地址1.2、下载后导入所安装机器1.3、yum安装解决依赖1.4、启动grafana1.5、查看端口是否启用&#xff08;端口默认3000&#xff09;1.6、浏览器访问 二、添加zabbix数据源2.1、导入数据源 **下一篇 我们讲讲构建仪表板的操作** 今天&#x…

如何在工作中利用AIGC提质增效?

引言 人工智能技术快速发展&#xff0c;以 ChatGPT 为代表的新的人工智能语言模型的出现与更迭&#xff0c;引发人们极大的兴奋和关注。越来越多的企业开始将 AI 技术应用到生产流程&#xff0c;以提高工作效率和生产力。AIGC&#xff08;AI Generated Content&#xff09;是人…

UE4/UE5 照明构建失败 “Lightmass crashed”解决“数组索引越界”

在构建全局光照时,经常会出现“Lightmass crashed”的错误,导致光照构建失败。本文将分析这一问题的原因,并给出解决建议。 UE4 版本4.26 报错如下&#xff1a; <None> Lightmass crashed: Assertion failed: (Index > 0) & (Index < ArrayNum) [File:d:\bu…

在 ubuntu 18.04 上使用源码升级 OpenSSH_7.6p1到 OpenSSH_9.3p1

1、检查系统已安装的当前 SSH 版本 使用命令 ssh -V 查看当前 ssh 版本&#xff0c;输出如下&#xff1a; OpenSSH_7.6p1 Ubuntu-4ubuntu0.7, OpenSSL 1.0.2n 7 Dec 20172、安装依赖&#xff0c;依次执行以下命令 sudo apt update sudo apt install build-essential zlib1g…

BOXTRADE-天启量化分析平台 主要功能介绍

BOXTRADE-天启量化分析平台 主要功能介绍 potato 数学 web 缘起 月晕而风&#xff0c;础润而雨 BOXTRADE-天启量化 欢迎来到天启量化&#xff01;这是一个专注于量化分析的网站。我们致力于为用户提供市场行情技术指标和量化策略分析方面的优质内容和资源。 我们的使命是 做…

第4章 微服务框架主体搭建

mini商城第4章 微服务框架主体搭建 一、课题 框架搭建 二、回顾 1、整体业务功能分析 2、根据业务需求设计表结构及字段 三、目标 1、版本控制器的搭建使用 2、能独立自主的搭建微服务框架 3、学会考虑一些公共的工具组件 4、网关模块的应用 四、内容 第1章 版本控…

万字长文·通俗易懂·一篇包掌握——输入/输出·文件操作(c语言超详细系列)(二)

前言&#xff1a;Hello&#xff0c;大家好&#x1f618;&#xff0c;我是心跳sy&#xff0c;上一节我们主要学习了格式化输入输出的基本内容&#xff0c;这一节我们对格式化进行更加深入的了解&#xff0c;对文件概念进行介绍&#xff0c;并且对输入、输出与文件读写的基本概念…