Jackson 2.x 系列【30】Spring Boot 集成之数据脱敏

2024-04-24 03:04

本文主要是介绍Jackson 2.x 系列【30】Spring Boot 集成之数据脱敏,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

有道无术,术尚可求,有术无道,止于术。

本系列Jackson 版本 2.17.0

本系列Spring Boot 版本 3.2.4

源码地址:https://gitee.com/pearl-organization/study-jaskson-demo

文章目录

    • 1. 概述
    • 2. 实现思路
    • 3. 案例演示
      • 3.1 脱敏规则
      • 3.2 自定义注解
      • 3.3 自定义序列化器
      • 3.4 测试

1. 概述

数据脱敏指对某些敏感信息通过脱敏规则进行数据的变形,实现敏感隐私数据的可靠保护。在开发、测试和其它非生产环境以及外包环境中安全地使用脱敏后的真实数据集。例如身份证号、手机号、卡号、客户号等个人信息都需要进行数据脱敏。

按照脱敏方式分为:

  • 静态数据脱敏:按照脱敏规则一次性完成大批量数据的变形转换处理
  • 动态数据脱敏:按照脱敏规则对于外部申请访问的数据进行即时处理并返回脱敏后的结果

随着 《网络安全法》 的颁布施行,对个人隐私数据的保护已经上升到法律层面。传统的应用系统普遍缺少对个人隐私数据的保护措施。数据脱敏,可实现在不需要对生产数据库中的数据进行任何改变的情况下,依据用户定义的脱敏规则,对生产数据库返回的数据进行专门的加密、遮盖和替换,确保生产环境的敏感数据能够得到保护。

2. 实现思路

一般可以在以下两种时机进行脱敏操作:

  • 数据库查询返回对象时
  • 序列化返回浏览器时
    在这里插入图片描述

Spring Web默认使用Jackson作为HTTP消息转换器的Json处理框架,那么可以自定义Jackson的序列化器对字段进行脱敏处理。

3. 案例演示

演示需求:

  • 身份证号显示为:43************6363
  • 手机号显示为:135****8888

3.1 脱敏规则

常用的脱敏规则有:

  • MD5:直接使用MD5计算
  • 遮盖脱敏:使用特殊字符遮盖,比如*
  • 替换脱敏:使用码表进行替换

演示需求中需要使用遮盖脱敏规则,将部分信息使用*进行遮盖。

3.2 自定义注解

参考Apache ShardingSphere的遮盖自 XY脱敏算法,定义一个脱敏注解,指定开始、结束位置,之间的字符都会使用指定的字符进行遮盖。

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.ANNOTATION_TYPE})
@JacksonAnnotationsInside
@JsonSerialize(using = MaskFromXToYJsonSerializer.class)
public @interface MaskFromXToYMask {/*** 起始位置 (从 0 开始计数)*/int from();/*** 结束位置(从 0 开始计数)*/int to();/*** 替换字符,默认**/String replaceChar() default "*";
}

定义身份证脱敏注解,遮盖2-13位置的字符:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside
@MaskFromXToYMask(from =2 ,to =13)
public @interface MaskIdNum {
}

定义手机号脱敏注解,遮盖3-6位置的字符:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside
@MaskFromXToYMask(from =3 ,to =6)
public @interface MaskPhone {
}

3.3 自定义序列化器

自定义序列化器MaskFromXToYJsonSerializer,获取字段上的脱敏注解,序列化时进行遮盖写出:

public class MaskFromXToYJsonSerializer extends StdSerializer<String> implements ContextualSerializer {private int from;private int to;private String replaceChar;public MaskFromXToYJsonSerializer(Class<String> t, int from, int to, String replaceChar) {super(t);this.from = from;this.to = to;this.replaceChar = replaceChar;}public MaskFromXToYJsonSerializer() {super(String.class);}/*** 序列化*/@Overridepublic void serialize(String str, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {// 1. 校验if (this.from >= this.to) {throw new RuntimeException("起始位置不能大于等于结束位置");}if (StrUtil.isEmpty(this.replaceChar)) {throw new RuntimeException("替换字符不能为空");}// 2. 序列化if (StrUtil.isEmpty(str)) {// 为空jsonGenerator.writeString("");} else if (str.length() <= this.from) {// 字符长度小于开始位置jsonGenerator.writeString(str);} else {// 脱敏写出char[] chars = str.toCharArray();int i = this.from;for (int minLength = Math.min(this.to, chars.length - 1); i <= minLength; ++i) {chars[i] = this.replaceChar.charAt(0);}jsonGenerator.writeString(new String(chars));}}/*** 根据字段注解,返回序列化器,仅在在第一次序列化时调用*/@Overridepublic JsonSerializer<?> createContextual(SerializerProvider serializers, BeanProperty property) throws JsonMappingException {// 1. 属性为 Nullif (property == null) {return serializers.findNullValueSerializer(null);}// 2. 属性的类型Class<?> rawClass = property.getType().getRawClass();if (CharSequence.class.isAssignableFrom(rawClass)) {// 3. 字符串类型,返回脱敏序列化器MaskFromXToYMask annotation = property.getAnnotation(MaskFromXToYMask.class);if (annotation == null) {annotation = property.getContextAnnotation(MaskFromXToYMask.class);}if (annotation != null) {return new MaskFromXToYJsonSerializer(String.class, annotation.from(), annotation.to(), annotation.replaceChar());}}return serializers.findValueSerializer(property.getType(), property);}
}

3.4 测试

定义一个用户对象,添加脱敏注解:

@Data
@ToString
public class UserVO implements Serializable {Long id;String username;List<String> roleList;@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")Date birthday;@MaskIdNumString idNum;@MaskPhoneString phone;
}

常见一个访问接口:

    @RequestMapping("/test")public UserVO test() {UserVO userVO = new UserVO();userVO.setId(1699657986705854464L);userVO.setUsername("jack");userVO.setBirthday(new Date());userVO.setIdNum("430852195602056363");userVO.setPhone("13536238888");List<String> roleList = new ArrayList<>();roleList.add("管理员");roleList.add("经理");userVO.setRoleList(roleList);return userVO;}

访问接口:

在这里插入图片描述

这篇关于Jackson 2.x 系列【30】Spring Boot 集成之数据脱敏的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/930589

相关文章

Java实现字节字符转bcd编码

《Java实现字节字符转bcd编码》BCD是一种将十进制数字编码为二进制的表示方式,常用于数字显示和存储,本文将介绍如何在Java中实现字节字符转BCD码的过程,需要的小伙伴可以了解下... 目录前言BCD码是什么Java实现字节转bcd编码方法补充总结前言BCD码(Binary-Coded Decima

SpringBoot全局域名替换的实现

《SpringBoot全局域名替换的实现》本文主要介绍了SpringBoot全局域名替换的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录 项目结构⚙️ 配置文件application.yml️ 配置类AppProperties.Ja

Java使用Javassist动态生成HelloWorld类

《Java使用Javassist动态生成HelloWorld类》Javassist是一个非常强大的字节码操作和定义库,它允许开发者在运行时创建新的类或者修改现有的类,本文将简单介绍如何使用Javass... 目录1. Javassist简介2. 环境准备3. 动态生成HelloWorld类3.1 创建CtC

JavaScript中的高级调试方法全攻略指南

《JavaScript中的高级调试方法全攻略指南》什么是高级JavaScript调试技巧,它比console.log有何优势,如何使用断点调试定位问题,通过本文,我们将深入解答这些问题,带您从理论到实... 目录观点与案例结合观点1观点2观点3观点4观点5高级调试技巧详解实战案例断点调试:定位变量错误性能分

Java实现将HTML文件与字符串转换为图片

《Java实现将HTML文件与字符串转换为图片》在Java开发中,我们经常会遇到将HTML内容转换为图片的需求,本文小编就来和大家详细讲讲如何使用FreeSpire.DocforJava库来实现这一功... 目录前言核心实现:html 转图片完整代码场景 1:转换本地 HTML 文件为图片场景 2:转换 H

Java使用jar命令配置服务器端口的完整指南

《Java使用jar命令配置服务器端口的完整指南》本文将详细介绍如何使用java-jar命令启动应用,并重点讲解如何配置服务器端口,同时提供一个实用的Web工具来简化这一过程,希望对大家有所帮助... 目录1. Java Jar文件简介1.1 什么是Jar文件1.2 创建可执行Jar文件2. 使用java

SpringBoot实现不同接口指定上传文件大小的具体步骤

《SpringBoot实现不同接口指定上传文件大小的具体步骤》:本文主要介绍在SpringBoot中通过自定义注解、AOP拦截和配置文件实现不同接口上传文件大小限制的方法,强调需设置全局阈值远大于... 目录一  springboot实现不同接口指定文件大小1.1 思路说明1.2 工程启动说明二 具体实施2

Java实现在Word文档中添加文本水印和图片水印的操作指南

《Java实现在Word文档中添加文本水印和图片水印的操作指南》在当今数字时代,文档的自动化处理与安全防护变得尤为重要,无论是为了保护版权、推广品牌,还是为了在文档中加入特定的标识,为Word文档添加... 目录引言Spire.Doc for Java:高效Word文档处理的利器代码实战:使用Java为Wo

SpringBoot日志级别与日志分组详解

《SpringBoot日志级别与日志分组详解》文章介绍了日志级别(ALL至OFF)及其作用,说明SpringBoot默认日志级别为INFO,可通过application.properties调整全局或... 目录日志级别1、级别内容2、调整日志级别调整默认日志级别调整指定类的日志级别项目开发过程中,利用日志

Java中的抽象类与abstract 关键字使用详解

《Java中的抽象类与abstract关键字使用详解》:本文主要介绍Java中的抽象类与abstract关键字使用详解,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、抽象类的概念二、使用 abstract2.1 修饰类 => 抽象类2.2 修饰方法 => 抽象方法,没有