如何通过 Jackson 的 StdSerializer 自定义处理复杂 Json 结构的脱敏与加密逻辑

秋涛姑娘_5924

秋涛姑娘_5924

2026-04-24

805人浏览

原创

应使用contextualserializer配合自定义注解实现字段级脱敏,而非stdserializer;因后者无法感知嵌套结构、类型信息与上下文,易导致类型擦除、空指针及策略失效。

如何通过 jackson 的 stdserializer 自定义处理复杂 json 结构的脱敏与加密逻辑

StdSerializer 本身不适合处理复杂 JSON 结构的脱敏与加密逻辑——它只面向单个字段值,无法感知嵌套对象、数组或字段间上下文关系。 真正该用的是 ContextualSerializer 配合自定义注解,否则你会在序列化深层字段时反复丢失类型信息、触发空指针、或把整个对象当成字符串粗暴脱敏。

为什么 StdSerializer 在复杂结构里会失效

当你写一个继承 StdSerializer<object></object> 的类,并试图在 serialize() 里做“如果字段名是 phone 就脱敏、如果是 idCard 就走另一套规则”,这看似可行,实则踩了三个坑:

  • Object 类型擦除后,你拿不到原始字段类型(比如是 User 还是 List<order></order>),value.getClass() 返回的常是 LinkedHashMap 或 String,根本没法做业务判断
  • 嵌套对象中的 phone 字段不会自动触发你的 StdSerializer,除非你显式给每一层都加 @JsonSerialize(using = ...),这等于放弃“自动”二字
  • 你无法从 SerializerProvider 中安全获取 Spring 上下文(比如当前用户角色、租户 ID),而这些恰恰是动态脱敏策略(如“管理员可见全量,普通用户仅见前3后4”)的必要输入

ContextualSerializer 才是正确入口点

真正能拿到字段元数据(包括注解、声明类型、泛型参数)的地方,是 ContextualSerializer 的 createContextual() 方法。它会在每个字段被序列化前调用一次,传入 BeanProperty —— 这才是你做条件分支的唯一可靠依据。

典型做法是:

  • 定义一个注解,比如 @Desensitize(strategy = PhoneStrategy.class, when = "user_role == 'GUEST'")
  • 在 createContextual() 中通过 property.getAnnotation(Desensitize.class) 拿到注解实例
  • 检查 property.getType().getRawClass() 是否为 String.class,避免对 Integer 或 LocalDateTime 错误应用脱敏
  • 根据注解参数 new 出对应策略实例(如 new PhoneStrategy(3, 4, "*")),并返回一个轻量级的 JsonSerializer<string></string> 匿名子类

注意:createContextual() 内不要 new 大对象、不要查 DB、不要调远程服务——它在每次字段序列化时都执行,性能敏感。

dmap-jsapi-skill
dmap-jsapi-skill

DMap GL地图JSAPI(dmapgl)开发指南。用于编写、审查、调试 DMap 地图 API 代码,涵盖地图初始化、覆盖物渲染、图层管理、事件处理、控件交互等任务。当用户提及 dmap、dmapgl、jsapi‑gl 或相关地图开发需求时自动触发。

下载

加密逻辑必须和序列化解耦

如果你真需要加密(比如 AES 加密手机号再 base64),别把它塞进 serialize()。原因很实际:

  • 加密密钥管理、加解密异常、IV 生成等逻辑和序列化职责无关,混在一起会让调试变困难
  • 加密结果通常是 byte[] 或 String,但 Jackson 默认会把 byte[] 序列为 base64 字符串——你若手动 gen.writeString(encrypted),反而可能多套一层 base64
  • 更关键的是:加密应发生在业务层或 DTO 构建阶段,而不是序列化临界点。否则同一个对象被多次序列化(如日志打印、缓存写入、HTTP 响应)就会重复加密,导致解密失败

推荐做法:在 Controller 返回前,用 AOP 或 DTO 构造器统一调用 EncryptionService.encrypt(phone),然后让 Jackson 按原样序列化加密后的字符串。脱敏和加密是两类动作,不该共用一个扩展点。

嵌套结构脱敏的唯一可靠方式是字段级控制

面对类似 Order → customer: { name, phone, address } → address: { street, city, zip } 这样的结构,你不能指望一个全局 StdSerializer 自动递归识别所有 phone 字段。Jackson 不会为你做字段名匹配遍历。

可行路径只有两条:

  • 在每个需脱敏的字段上明确标注注解,如 @Desensitize(type = DesensitizeType.PHONE),靠 ContextualSerializer 逐个处理
  • 用 @JsonSerialize(using = CustomerViewSerializer.class) 直接接管整个 Customer 对象序列化,在其 serialize() 里手动调用 jsonGen.writeObjectField("phone", masker.mask(customer.getPhone())) 等逻辑——但这丧失了复用性,且容易漏掉新增字段

前者是主流选择;后者只适合极少数强管控场景。别幻想“写一个 Serializer 解决所有嵌套脱敏”——那不是 Jackson 的设计哲学,而是给自己埋雷。

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

2023.06.15

10857

6

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

2023.07.05

7982

9

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

2023.07.31

6932

8

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.01

1164

3

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.02

948

3

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

1416

5

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

2869

5

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

2023.08.03

20151

3

配置java环境变量
配置java环境变量

配置Java环境变量是为了让操作系统能够识别和使用Java的相关命令和功能。本专题为大家提供配置java环境变量相关文章,帮助大家解决问题。

2023.08.03

1255

8

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WEB前端教程【HTML5+CSS3+JS】
WEB前端教程【HTML5+CSS3+JS】

共101课时 | 21万人学习

JS进阶与BootStrap学习
JS进阶与BootStrap学习

共39课时 | 4.9万人学习