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

Spring Boot 可扩展脱敏框架设计全解析 | 注解+策略模式+模板方法模式实战

一、需求场景:为什么需要脱敏框架?

在数据安全合规要求下,敏感信息处理成为系统必备能力。典型场景:

  • 用户隐私保护(手机号、身份证、邮箱等)
  • 日志敏感信息过滤
  • 接口返回数据自动脱敏

传统方案痛点:

  • 硬编码脱敏逻辑,维护成本高
  • 不同字段需重复编写相似代码
  • 无法动态调整脱敏规则

二、框架设计全景图

脱敏注解
Jackson序列化器
脱敏处理器
正则处理器
滑动窗口处理器
自定义处理器

三、核心实现三步走

1. 注解体系设计(声明式配置)

顶级脱敏注解

@Documented
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside // 此注解是其他所有 jackson 注解的元注解,打上了此注解的注解表明是 jackson 注解的一部分
@JsonSerialize(using = StringDesensitizeSerializer.class) // 指定序列化器
public @interface DesensitizeBy {/*** 脱敏处理器*/@SuppressWarnings("rawtypes")Class<? extends DesensitizationHandler> handler();}

邮箱脱敏注解

@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@DesensitizeBy(handler = EmailDesensitizationHandler.class)
public @interface EmailDesensitize {/*** 匹配的正则表达式*/String regex() default "(^.)[^@]*(@.*$)";/*** 替换规则,邮箱;** 比如:example@gmail.com 脱敏之后为 e****@gmail.com*/String replacer() default "$1****$2";/*** 是否禁用脱敏** 支持 Spring EL 表达式,如果返回 true 则跳过脱敏*/String disable() default "";}

2. 处理机制实现(策略模式+模板方法模式)

脱敏处理器

public interface DesensitizationHandler<T extends Annotation> {/*** 脱敏** @param origin     原始字符串* @param annotation 注解信息* @return 脱敏后的字符串*/String desensitize(String origin, T annotation);/*** 是否禁用脱敏的 Spring EL 表达式** 如果返回 true 则跳过脱敏** @param annotation 注解信息* @return 是否禁用脱敏的 Spring EL 表达式*/default String getDisable(T annotation) {// 约定:默认就是 enable() 属性。如果不符合,子类重写try {return (String) ReflectUtil.invoke(annotation, "disable");} catch (Exception ex) {return "";}}}

正则表达式脱敏处理器抽象类(模板方法模式+策略模式)

public abstract class AbstractRegexDesensitizationHandler<T extends Annotation>implements DesensitizationHandler<T> {
//==========================================不可变部分即公共方法即模板方法模式的实现===========================@Overridepublic String desensitize(String origin, T annotation) {// 1. 判断是否禁用脱敏Object disable = SpringExpressionUtils.parseExpression(getDisable(annotation));if (Boolean.TRUE.equals(disable)) {return origin;}// 2. 执行脱敏String regex = getRegex(annotation);String replacer = getReplacer(annotation);return origin.replaceAll(regex, replacer);}//==========================================可变部分抽象由具体子类实现===========================/*** 获取注解上的 regex 参数** @param annotation 注解信息* @return 正则表达式*/abstract String getRegex(T annotation);/*** 获取注解上的 replacer 参数** @param annotation 注解信息* @return 待替换的字符串*/abstract String getReplacer(T annotation);}

EmailDesensitize的脱敏处理器

//==========================================邮箱脱敏策略===========================public class EmailDesensitizationHandler extends AbstractRegexDesensitizationHandler<EmailDesensitize> {@OverrideString getRegex(EmailDesensitize annotation) {return annotation.regex();}@OverrideString getReplacer(EmailDesensitize annotation) {return annotation.replacer();}}

3. Jackson序列化集成

脱敏序列化器

public class StringDesensitizeSerializer extends StdSerializer<String> implements ContextualSerializer {@Getter@Setterprivate DesensitizationHandler desensitizationHandler;protected StringDesensitizeSerializer() {super(String.class);}@Overridepublic JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) {DesensitizeBy annotation = beanProperty.getAnnotation(DesensitizeBy.class);if (annotation == null) {return this;}// 创建一个 StringDesensitizeSerializer 对象,使用 DesensitizeBy 对应的处理器StringDesensitizeSerializer serializer = new StringDesensitizeSerializer();serializer.setDesensitizationHandler(Singleton.get(annotation.handler()));return serializer;}@Override@SuppressWarnings("unchecked")public void serialize(String value, JsonGenerator gen, SerializerProvider serializerProvider) throws IOException {if (StrUtil.isBlank(value)) {gen.writeNull();return;}// 获取序列化字段Field field = getField(gen);// 自定义处理器DesensitizeBy[] annotations = AnnotationUtil.getCombinationAnnotations(field, DesensitizeBy.class);if (ArrayUtil.isEmpty(annotations)) {gen.writeString(value);return;}for (Annotation annotation : field.getAnnotations()) {if (AnnotationUtil.hasAnnotation(annotation.annotationType(), DesensitizeBy.class)) {value = this.desensitizationHandler.desensitize(value, annotation);gen.writeString(value);return;}}gen.writeString(value);}/*** 获取字段** @param generator JsonGenerator* @return 字段*/private Field getField(JsonGenerator generator) {String currentName = generator.getOutputContext().getCurrentName();Object currentValue = generator.getCurrentValue();Class<?> currentValueClass = currentValue.getClass();return ReflectUtil.getField(currentValueClass, currentName);}}

四、使用示例:三步完成脱敏

1. 添加注解

public class UserVO {@EmailDesensitize(replacer = "$1***$2") // 自定义替换规则private String email;@PhoneDesensitize // 使用默认手机号脱敏规则private String phone;
}

2. 返回结果对比

// 原始数据
{"email": "test@example.com","phone": "13812345678"
}// 脱敏后
{"email": "t***@example.com","phone": "138****5678"
}

3. 动态关闭脱敏(SpEL支持)

@EmailDesensitize(disable = "${app.desensitize.disable:false}")
private String email;

五、设计亮点分析

1. 开闭原则实践

100% 0% 扩展成本对比 新增脱敏类型 修改核心逻辑
  • 新增类型:只需添加注解+处理器
  • 修改规则:调整注解参数即可

2. 性能优化点

  • 单例模式:处理器全局单例复用
  • 缓存机制:注解解析结果缓存
  • 懒加载:按需初始化处理器

3. 灵活配置能力

// 多规则叠加示例
@EmailDesensitize(regex = "(?<=.{2}).", replacer = "*")
@ConditionalOnProperty("security.enabled")
private String email;

相关文章:

Spring Boot 可扩展脱敏框架设计全解析 | 注解+策略模式+模板方法模式实战

一、需求场景&#xff1a;为什么需要脱敏框架&#xff1f; 在数据安全合规要求下&#xff0c;敏感信息处理成为系统必备能力。典型场景&#xff1a; 用户隐私保护&#xff08;手机号、身份证、邮箱等&#xff09;日志敏感信息过滤接口返回数据自动脱敏 传统方案痛点&#xf…...

STM32F103_LL库+寄存器学习笔记13 - 梳理外设CAN与如何发送CAN报文(串行发送)

导言 CAN总线因其高速稳定的数据传输与卓越抗干扰性能&#xff0c;在汽车、机器人及工业自动化中被广泛应用。它采用分布式网络结构&#xff0c;实现多节点间实时通信&#xff0c;确保各控制模块精准协同。在汽车领域&#xff0c;CAN总线连接发动机、制动、车身系统&#xff0c…...

JavaScript学习19-事件类型之鼠标事件

1. 2. 3....

Linux系统调用编程

文章目录 一、进程和线程二、Linux的虚拟内存管理和stm32的真实物理内存**Linux虚拟内存管理**STM32物理内存映射2. 主要区别 三、Linux系统调用函数 fork()、wait()、exec()1. fork()&#xff1a;创建子进程2. wait()&#xff1a;等待子进程状态改变3. exec()&#xff1a;替换…...

游戏引擎学习第203天

回顾当前情况 在这里我将直播完成整个游戏的制作。我们现在面临一些技术上的困难&#xff0c;确实如此。我的笔记本电脑的电源接口坏了&#xff0c;所以我不得不准备了这台备用笔记本&#xff0c;希望它能够正常工作。我所以希望一切都还好&#xff0c;尽管我不完全确定是否一…...

408 计算机网络 知识点记忆(4)

前言 本文基于王道考研课程与湖科大计算机网络课程教学内容&#xff0c;系统梳理核心知识记忆点和框架&#xff0c;既为个人复习沉淀思考&#xff0c;亦希望能与同行者互助共进。&#xff08;PS&#xff1a;后续将持续迭代优化细节&#xff09; 往期内容 408 计算机网络 知识…...

线性代数:分块矩阵,秩,齐次线性,非齐次线性的解相关经典例题

所以C错误&#xff0c;选D 排除A&#xff0c;B选项...

Nginx功能及应用全解:从负载均衡到反向代理的全面剖析

Nginx作为一款开源的高性能HTTP服务器和反向代理服务器&#xff0c;凭借其高效的资源利用率和灵活的配置方式&#xff0c;已成为互联网领域中最受欢迎的Web服务器之一。无论是作为HTTP服务器、负载均衡器&#xff0c;还是作为反向代理和缓存服务器&#xff0c;Nginx的多种功能广…...

深度学习数据集划分比例多少合适

在机器学习和深度学习中&#xff0c;测试集的划分比例需要根据数据量、任务类型和领域需求灵活调整。 1. 常规划分比例 通用场景 训练集 : 验证集 : 测试集 60% : 20% : 20% 适用于大多数中等规模数据集&#xff08;如数万到数十万样本&#xff09;&#xff0c;平衡了训练数…...

CExercise_1_5 水仙花数

题目&#xff1a; 经典循环案例&#xff1a;请求出所有的水仙花数&#xff0c;并统计总共有几个。 所谓的水仙花数是指一个三位数&#xff0c;其各位数字的立方和等于该数本身。 举例&#xff1a;153就是一个水仙花数&#xff0c;153 1 * 1 * 1 5 * 5 * 5 3 * 3 * 3 1 125…...

用C实现一个最简单的正则表达式引擎

用C实现一个简单的正则表达式引擎 下面我将实现一个极简的正则表达式引擎&#xff0c;仅支持以下基本功能&#xff1a; . 匹配任意单个字符* 匹配零个或多个前导字符^ 匹配字符串开头$ 匹配字符串结尾 完整代码实现 #include <stdio.h> #include <stdbool.h>bo…...

哈密尔顿路径(Hamiltonian Path)及相关算法题目

哈密尔顿路径要求访问图中每个顶点恰好一次&#xff0c;通常用于解决旅行商问题&#xff08;TSP&#xff09;或状态压缩DP问题。 哈密尔顿路径&#xff08;Hamiltonian Path&#xff09;是指在一个图中经过每个顶点恰好一次的路径。如果这条路径的起点和终点相同&#xff08;即…...

MINIQMT学习课程Day10

开始获取股票数据课程的学习&#xff1a; 获取qmt账号的持仓情况后&#xff0c;我们进入下一步&#xff0c;如何获得当前账号的委托状况 还是之前的步骤&#xff0c;打开qmt&#xff0c;选择独立交易&#xff0c; 之后使用pycharm&#xff0c;编写py文件 导入包&#xff1a…...

JAVA实战开源项目:智慧图书管理系统(Vue+SpringBoot) 附源码

本文项目编号 T 152 &#xff0c;文末自助获取源码 \color{red}{T152&#xff0c;文末自助获取源码} T152&#xff0c;文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…...

Linux 系统管理综合实训 —— 基于 NAT 模式的多 IP 配置、Nginx 服务部署及存储管理

1. 虚拟机网络配置&#xff1a;NAT模式与多IP地址设置 将你的虚拟机的网卡模式设置为nat模式&#xff0c;给虚拟机网卡配置三个主机位分别为100、200、168的ip地址 设置静态IP [rootlocalhost ~]# nmcli c modify ens160 ipv4.method manual ipv4.addresses 192.168.2.100/2…...

如何在windows 环境、且没有显卡的情况下用python跑通从ModelScope下载的大模型的调用

文章目录 背景介绍源代码&#xff1a;安装调试过程1.设置第三方镜像源2.预先安装&#xff1a;3.在python中创建代码&#xff1a;4.最终修改程序,将device_map从“cuda”改成“auto”&#xff0c;大模型调用1.5B&#xff08;1___5B)的5.最终跑出结果解释&#xff1a;示例&#x…...

黑马点评redis改 part 1

本篇将主要阐述短信登录的相关知识&#xff0c;感谢黑马程序员开源&#xff0c;感谢提供初始源文件&#xff08;给到的是实战第7集开始的代码&#xff09;【Redis实战篇】黑马点评学习笔记&#xff08;16万字超详细、Redis实战项目学习必看、欢迎点赞⭐收藏&#xff09;-CSDN博…...

Apache Struts2 漏洞(CVE-2017-5638)技术分析

一、漏洞简介 CVE-2017-5638 是 Apache Struts2 中的一个远程命令执行漏洞&#xff0c;攻击者可以通过构造特定的 HTTP 请求头&#xff0c;利用Struts的 OGNL 表达式解析机制&#xff0c;在服务器端执行任意代码。 二、漏洞触发场景 漏洞存在于 Struts2 的 Jakarta Multipar…...

A2DP(Advanced Audio Distribution Profile)是蓝牙协议栈中用于音频传输的一个标准化协议

A2DP&#xff08;Advanced Audio Distribution Profile&#xff09;是蓝牙协议栈中用于音频传输的一个标准化协议&#xff0c;主要用于高质量音频流的无线传输。以下是A2DP协议的详细信息&#xff1a; 定义 A2DP协议允许音源设备&#xff08;Source&#xff0c;简称SRC&#…...

【Ragflow】11. 文件解析流程分析/批量解析实现

概述 本文继续对ragflow文档解析部分进行分析&#xff0c;并通过脚本的方式实现对文件的批量上传解析。 文件解析流程 文件解析的请求处理流程大致如下&#xff1a; 1.前端上传文件&#xff0c;通过v1/document/run接口&#xff0c;发起文件解析请求 2.后端api\apps\docum…...

第三期:深入理解 Spring Web MVC [特殊字符](数据传参+ 特殊字符处理 + 编码问题解析)

✨前言&#xff1a;传参和状态管理&#xff0c;看似简单其实门道不少 在 Web 开发中&#xff0c;前端和后端最核心的交流方式就是“传参”&#xff0c;而“传参”除了涉及如何写代码获取参数&#xff0c;还藏着很多开发者容易忽略的细节&#xff1a; 为什么 URL 带了中文&…...

嵌入式学习笔记——ARM-中断与异常

文章目录 中断与异常的区别中断与 DMA 的区别中断能否睡眠&#xff1f;下半部能否睡眠&#xff1f;1. 中断处理程序不能睡眠2. 下半部&#xff08;SoftIRQ、Tasklet、Workqueue&#xff09; 中断处理注意点1. 快进快出2. 避免阻塞3. 正确返回值4. 如何处理大量任务5. 避免竞态问…...

Everything 安装教程与使用教程(附安装包)

文章目录 前言一、Everything 介绍二、Everything 安装教程1.Everything 安装包下载2.选择安装文件3.选择安装语言4.接受许可协议5.选择安装位置6.配置安装选项7.完成安装 三、Everything 使用教程1.启动软件2.简单关键词搜索3.按类型搜索 前言 在日常使用电脑时&#xff0c;随…...

嵌入式开发中栈溢出的处理方法

嵌入式开发中栈溢出的处理方法 目录 引言栈溢出的原理栈溢出的危害栈溢出检测方法 哨兵变量法栈着色法硬件监测机制编译器栈保护 裸机系统中的栈溢出处理操作系统中的栈溢出处理预防栈溢出的最佳实践结论 引言 在嵌入式系统开发中&#xff0c;栈溢出是一个常见且危险的问题…...

SQL语句(三)—— DQL

目录 基本语法 一、基础查询 1、查询多个字段 2、字段设置别名 3、去除重复记录 4、示例代码 二、条件查询 1、语法 2、条件列表常用的运算符 3、示例代码 三、分组查询 &#xff08;一&#xff09;聚合函数 1、介绍 2、常见的聚合函数 3、语法 4、示例代码 &…...

#python项目生成exe相关了解

在 Windows 上将 Python 项目 生成 EXE 可执行文件&#xff0c;主要使用 pyinstaller。以下是完整步骤&#xff1a; &#x1f4cc; 1. 安装 PyInstaller pip install pyinstaller如果已安装&#xff0c;可执行以下命令检查版本&#xff1a; pyinstaller --version&#x1f4c…...

Opencv计算机视觉编程攻略-第九节 描述和匹配兴趣点

一般而言&#xff0c;如果一个物体在一幅图像中被检测到关键点&#xff0c;那么同一个物体在其他图像中也会检测到同一个关键点。图像匹配是关键点的常用功能之一&#xff0c;它的作用包括关联同一场景的两幅图像、检测图像中事物的发生地点等等。 1.局部模板匹配 凭单个像素就…...

JSON-lib考古现场:在2025年打开赛博古董店的奇妙冒险

各位在代码海洋里捡贝壳的探险家们&#xff01;今天我们要打开一个尘封的Java古董箱——JSON-lib&#xff01;这货可是2003年的老宝贝&#xff0c;比在座很多程序员的工龄还大&#xff01;准备好穿越回Web 1.0时代&#xff0c;感受XML统治时期的余晖了吗&#xff1f; &#x1f…...

Android: Handler 的用法详解

Android 中 Handler 的用法详解 Handler 是 Android 中用于线程间通信的重要机制&#xff0c;主要用于在不同线程之间发送和处理消息。以下是 Handler 的全面用法指南&#xff1a; 一、Handler 的基本原理 Handler 基于消息队列(MessageQueue)和循环器(Looper)工作&#xff0c…...

汇编学习之《push , pop指令》

学习本章前线了解ESP, EBP 指令 汇编学习之《指针寄存器&大小端学习》-CSDN博客 栈的特点&#xff1a; 好比一个垂直容器&#xff0c;可以陆续放入物体&#xff0c;但是先放的物体通常会被后面放的物体压着&#xff0c;只有等上面后放的物品拿出来后&#xff0c;才能…...