如何在Java DTO中对自定义注解字段进行日志脱敏?
日志敏感字段脱敏实现方案
基于Jackson自定义注解的脱敏方案
步骤1:定义自定义脱敏注解
创建@Censored注解,标记需要脱敏的字段:
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) public @interface Censored { }
步骤2:实现Jackson上下文序列化器
编写序列化器,识别带@Censored注解的字段并替换为***:
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.BeanProperty; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.ser.ContextualSerializer; import java.io.IOException; public class CensoredSerializer extends JsonSerializer<Object> implements ContextualSerializer { private boolean needCensor; @Override public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException { if (needCensor) { gen.writeString("***"); } else { gen.writeObject(value); } } @Override public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) { Censored annotation = property.getAnnotation(Censored.class); this.needCensor = annotation != null; return this; } }
步骤3:配置ObjectMapper注册序列化器
创建全局ObjectMapper实例,将自定义序列化器注册进去:
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; public class ObjectMapperConfig { public static ObjectMapper getCensoredObjectMapper() { ObjectMapper objectMapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); module.addSerializer(Object.class, new CensoredSerializer()); objectMapper.registerModule(module); return objectMapper; } }
步骤4:使用示例
在DTO字段上添加@Censored注解,序列化时自动脱敏:
public class Person { private String name; @Censored private String secret; // 构造器、getter、setter省略 } // 测试序列化 public class CensorTest { public static void main(String[] args) throws Exception { Person person = new Person("Alice", "my-secret-123"); ObjectMapper mapper = ObjectMapperConfig.getCensoredObjectMapper(); String json = mapper.writeValueAsString(person); // 输出结果: {"name":"Alice","secret":"***"} System.out.println(json); } }
其他日志脱敏实现方案
- 日志框架自定义转换器:以Logback为例,实现
Converter接口,在convert方法中匹配日志内容里的敏感字段(如手机号、密码)并替换为脱敏字符,然后在配置文件中指定使用该转换器处理日志消息。 - AOP切面拦截:利用Spring AOP或AspectJ,拦截日志输出方法(如
Logger.debug()/info()),对方法参数中的DTO对象进行脱敏处理——复制对象后替换敏感字段值,再传递给日志方法输出。 - 第三方脱敏工具库:使用现成的脱敏组件,通过注解或配置规则快速实现字段脱敏,无需手动编写序列化逻辑。
- DTO复制脱敏:日志输出前手动复制DTO对象,将敏感字段值替换为
***后再序列化输出。这种方式简单直接,但需要维护复制逻辑,适合小范围场景。
内容的提问来源于stack exchange,提问作者Baksa Zoltán
相关产品推荐
相关产品推荐

