一个注解让 Spring Boot 项目接口返回数据脱敏
1 背景
需求是某些接口返回的信息,涉及到敏感数据的必须进行脱敏操作
2 思路
①要做成可配置多策略的脱敏操作,要不然一个个接口进行脱敏操作,重复的工作量太多,很显然违背了“多写一行算我输”的程序员规范。思来想去,定义数据脱敏注解和数据脱敏逻辑的接口, 在返回类上,对需要进行脱敏的属性加上,并指定对应的脱敏策略操作。
②接下来我只需要拦截控制器返回的数据,找到带有脱敏注解的属性操作即可,一开始打算用 @ControllerAdvice 去实现,但发现需要自己去反射类获取注解。当返回对象比较复杂,需要递归去反射,性能一下子就会降低,于是换种思路,我想到平时使用的 @JsonFormat,跟我现在的场景很类似,通过自定义注解跟字段解析器,对字段进行自定义解析,tql。
3 实现代码
3.1自定义数据注解,并可以配置数据脱敏策略:
package com.wkf.workrecord.tools.desensitization;
import java.lang.annotation.*;
/**
* 注解类
* @author wuKeFan
* @date 2023-02-20 09:36:39
*/
@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataMasking {
DataMaskingFunc maskFunc() default DataMaskingFunc.NO_MASK;
}
3.2 自定义 Serializer,参考 jackson 的 StringSerializer,下面的示例只针对 String 类型进行脱敏
DataMaskingOperation.class:
package com.wkf.workrecord.tools.desensitization;
/**
* 接口脱敏操作接口类
* @author wuKeFan
* @date 2023-02-20 09:37:48
*/
public interface DataMaskingOperation {
String MASK_CHAR = “*”;
String mask(String content, String maskChar);
}
DataMaskingFunc.class:
package com.wkf.workrecord.tools.desensitization;
import org.springframework.util.StringUtils;
/**
* 脱敏转换操作枚举类
* @author wuKeFan
* @date 2023-02-20 09:38:35
*/
public enum DataMaskingFunc {
/**
* 脱敏转换器
*/
NO_MASK((str, maskChar) -> {
return str;
}),
ALL_MASK((str, maskChar) -> {
if (StringUtils.hasLength(str)) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
sb.append(StringUtils.hasLength(maskChar) ? maskChar : DataMaskingOperation.MASK_CHAR);
}
return sb.toString();
} else {
return str;
}
});
private final DataMaskingOperation operation;
private DataMaskingFunc(DataMaskingOperation operation) {
this.operation = operation;
}
public DataMaskingOperation operation() {
return this.operation;
}
}
DataMaskingSerializer.class:
package com.wkf.workrecord.tools.desensitization;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.fasterxml.jackson.databind.ser.std.StdScalarSerializer;
import java.io.IOException;
import java.util.Objects;
/**
* 自定义Serializer
* @author wuKeFan
* @date 2023-02-20 09:39:47
*/
public final class DataMaskingSerializer extends StdScalarSerializer {
private final DataMaskingOperation operation;
public DataMaskingSerializer() {
super(String.class, false);
this.operation = null;
}
public DataMaskingSerializer(DataMaskingOperation operation) {
super(String.class, false);
this.operation = operation;
}
public boolean isEmpty(SerializerProvider prov, Object value) {
String str = (String)value;
return str.isEmpty();
}
public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException {
if (Objects.isNull(operation)) {
String content = DataMaskingFunc.ALL_MASK.operation().mask((String) value, null);
gen.writeString(content);
} else {
String content = operation.mask((String) value, null);
gen.writeString(content);
}
}
public final void serializeWithType(Object value, JsonGenerator gen, SerializerProvider provider, TypeSerializer typeSer) throws IOException {
this.serialize(value, gen, provider);
}
public JsonNode getSchema(SerializerProvider provider) {
return this.createSchemaNode(“string”, true);
}
public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint) throws JsonMappingException {
this.visitStringFormat(visitor, typeHint);
}
}
3.3 自定义 AnnotationIntrospector,适配我们自定义注解返回相应的 Serializer
package com.wkf.workrecord.tools.desensitization;
import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.introspect.NopAnnotationIntrospector;
import lombok.extern.slf4j.Slf4j;
/**
* @author wuKeFan
* @date 2023-02-20 09:43:41
*/
@Slf4j
public class DataMaskingAnnotationIntroSpector extends NopAnnotationIntrospector {
@Override
public Object findSerializer(Annotated am) {
DataMasking annotation = am.getAnnotation(DataMasking.class);
if (annotation != null) {
return new DataMaskingSerializer(annotation.maskFunc().operation());
}
return null;
}
}
3.4 覆盖 ObjectMapper:
package com.wkf.workrecord.tools.desensitization;
import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
/**
* 覆盖 ObjectMapper
* @author wuKeFan
* @date 2023-02-20 09:44:35
*/
@Configuration(proxyBeanMethods = false)
public class DataMaskConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({Jackson2ObjectMapperBuilder.class})
static class JacksonObjectMapperConfiguration {
JacksonObjectMapperConfiguration() {
}
@Bean
@Primary
ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
AnnotationIntrospector ai = objectMapper.getSerializationConfig().getAnnotationIntrospector();
AnnotationIntrospector newAi = AnnotationIntrospectorPair.pair(ai, new DataMaskingAnnotationIntroSpector());
objectMapper.setAnnotationIntrospector(newAi);
return objectMapper;
}
}
}
3.5 返回对象加上注解:
package com.wkf.workrecord.tools.desensitization;
import lombok.Data;
import java.io.Serializable;
/**
* 需要脱敏的实体类
* @author wuKeFan
* @date 2023-02-20 09:35:52
*/
@Data
public class User implements Serializable {
/**
* 主键ID
*/
private Long id;
/**
* 姓名
*/
@DataMasking(maskFunc = DataMaskingFunc.ALL_MASK)
private String name;
/**
* 年龄
*/
private Integer age;
/**
* 邮箱
*/
@DataMasking(maskFunc = DataMaskingFunc.ALL_MASK)
private String email;
}
4 测试
我们写一个Controller测试一下看是不是我们需要的效果
4.1 测试的Controller类DesensitizationController.class如下:
package com.wkf.workrecord.tools.desensitization;
import com.biboheart.brick.model.BhResponseResult;
import com.wkf.workrecord.utils.ResultVOUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* 测试接口脱敏测试控制类
* @author wuKeFan
* @date 2022-06-21 17:23
*/
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping(“/desensitization/”)
public class DesensitizationController {
@RequestMapping(value = “test”, method = {RequestMethod.GET, RequestMethod.POST})
public BhResponseResult test() {
User user = new User();
user.setAge(1);
user.setEmail(“123456789@qq.com”);
user.setName(“吴名氏”);
user.setId(1L);
return ResultVOUtils.success(user);
}
}
4.2 PostMan接口请求,效果符合预期,如图:
————————————————
版权声明:本文为CSDN博主「吴名氏.」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_37284798/article/details/129118284
相关文章:
一个注解让 Spring Boot 项目接口返回数据脱敏
1 背景 需求是某些接口返回的信息,涉及到敏感数据的必须进行脱敏操作 2 思路 ①要做成可配置多策略的脱敏操作,要不然一个个接口进行脱敏操作,重复的工作量太多,很显然违背了“多写一行算我输”的程序员规范。思来想去ÿ…...
测试人员的KPI怎么设置
关于测试部的KPI,简单列举下自己所经历部门的考核指标: 工作量。根据平时跟踪的需求,编写的用例,提交的bug数等综合评估; 负责项目的质量。上线项目是否出现重大功能的事故, 如果出现了事故,分…...
Databend 开源周报第 116 期
Databend 是一款现代云数仓。专为弹性和高效设计,为您的大规模分析需求保驾护航。自由且开源。即刻体验云服务:https://app.databend.cn 。 Whats On In Databend 探索 Databend 本周新进展,遇到更贴近你心意的 Databend 。 特性预览&#…...
mongodb-gridfs下载文件报Sort exceeded memory limit of 104857600 bytes异常
报错详细信息 com.mongodb.MongoQueryException: Query failed with error code 292 and error message Executor error during find command :: caused by :: Sort exceeded memory limit of 104857600 bytes, but did not opt in to external sorting. on server 11.51.141.…...
分享一下微信小程序里怎么实现扫码点餐链接
在当今数字化时代,扫码点餐已经成为了餐饮行业的一种趋势。通过微信小程序,实现扫码点餐功能,可以为餐厅带来诸多便利和优势。本文将详细介绍如何在微信小程序中实现扫码点餐功能,帮助餐厅提高服务效率和质量,提升用户…...
安卓开发环境安装教程
在本教程中,我将向您介绍如何在Windows操作系统上安装Android开发环境。Android开发环境包括Java Development Kit(JDK),Android Studio IDE和相应的SDK工具。跟随以下步骤,您将能够搭建安卓开发环境并开始开发自己的应…...
深入探究Selenium定位技巧及最佳实践
在使用Selenium进行Web自动化测试时,准确地定位元素是非常重要的一步。Selenium提供了多种元素定位方法,本文将深入探究这八大元素定位方法,帮助读者更好地理解和应用Selenium的定位技巧。 1. ID定位 ID是元素在HTML中的唯一标识符ÿ…...
如何正确安装psycopg2,No module named ‘psycopg2._psycopg‘解决
二、psycopg2安装方法 psycopg2可以通过多种方式安装,我们这里介绍两种常用的方式:通过pip安装和手动安装。 1、通过pip安装psycopg2 如果已经安装了pip,那么在命令行中输入以下命令即可完成psycopg2的安装: pip install psyc…...
go WriteFile文件追加写入(适合小文件)
go 在做文件追加写入时一般用os.OpenFile 指定 FileMode 为 os.O_APPEND. 如官方文档示例: f, err : os.OpenFile("access.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)if err ! nil {log.Fatal(err)}if _, err : f.Write([]byte("appended some data\n&…...
history 模式上线需要注意什么事项?
结论先行: 首先,需要在服务器上对所有的路由路径进行配置,避免在访问路由时出现 404 的情况; 其次,需要特别注意安全性和兼容性问题。 因为使用 History 模式会暴露出服务器上的文件路径,因此在部署时需要…...
VMware虚拟机安装Ubuntu22.04教程(2023最新最详细)
目录 简介 1 VMware虚拟机下载与安装 2 Ubuntu操作系统安装与配置 2.1 Ubuntu虚拟机配置 2.2 Ubuntu操作系统安装 简介 Linux是一种自由和开放源代码的操作系统内核,被广泛应用于各种计算机系统中。它以稳定性、安全性和灵活性而闻名,并成为服务器…...
yakit使用爆破编码明文_dnslog使用
yakit使用爆破编码密码 文章目录 yakit使用爆破编码密码yakit使用1 yakit编码密码进行爆破2 准备eval.php文件放入web3 访问http://192.168.225.206/eval.php,使用bp抓包,测试后环境准本好4 使用yakit4.1 进入页面,点击这里进行配置默认端口80834.2 发送到模糊测试4…...
3分钟教你用Python+Appium实现自动化测试
一、环境准备 1.脚本语言:Python3.x IDE:安装Pycharm 2.安装Java JDK 、Android SDK 3.adb环境,path添加E:\Software\Android_SDK\platform-tools 4.安装Appium for windows,官网地址 Redirecting 点击下载按钮会到GitHub…...
qt的一些自绘控件
https://download.csdn.net/download/venice0708/88469835...
类图表示法
设计模式,用设计图表示的话,主要用到类图。常见UML类图如下: 1、类图:矩形框,代表一个类(Class)。类图分为三层,第一层显示类的名称,如果是抽象类,则用斜体显…...
大模型训练框架
一文搞定分布式训练:dataparallel、distirbuted、deepspeed、accelerate、transformers、horovod - 知乎代码地址:taishan1994/pytorch-distributed-NLP: pytorch分布式训练 (github.com)pytorch-distributed-NLPpytorch单机多卡分布式训练-中文文本分类…...
好用的Visio绘图文件工具 VSD Viewer最新 for mac
VSD Viewer是一款可以查看Microsoft Visio绘图文件的工具,适用于Windows和macOS操作系统。它具有以下优点: 直观易用:VSD Viewer的用户界面非常简单直观,易于使用。支持多种文件格式:VSD Viewer支持多种Visio文件格式…...
三代自动驾驶系统及主流科技公司自动驾驶技术方案简介
截止目前,按技术特点,自动驾驶技术大致经历了三代发展:第一代自动驾驶技术以后融合感知技术,高精度地图,基于惯导、GPS定位系统,预测模块,基于优化、搜索的规控等组成。第一代比较成熟的自动驾驶…...
mac安装nodejs,跑vue程序
1. 下载node.js for mac,地址:Node.js。一路安装就可以了,无需修改。 2. mac终端,查看node和npm的版本。 3. 配置环境变量, vim .bash_profile增加PATH$PATH:/usr/local/bin/ 4. 但是毕竟npm安装一些东西还是太慢了所…...
VC++程序崩溃时,使用Visual Studio静态分析dump文件
1、通过Visual Studio直接把Dump文件打开 2、点击【仅限本机进行调试】,启动Dump 3.1、本机调试启动后,如果程序运行模块和pdb文件在同一个目录的,直接定位到异常代码行 3.2、如果显示找不到pdb文件,则需要通过【新建路径】设置…...
SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...
C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
