自定义一个 Jackson 转换注解完成敏感数据的隐藏
Posted 毕小宝
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自定义一个 Jackson 转换注解完成敏感数据的隐藏相关的知识,希望对你有一定的参考价值。
背景
Spring 将响应数据转换为前端 JSON 字符串时,有一些特殊需求,例如数据库中时间字段为 Long 类型,转换为 JSON 需要是时间字符串,有些敏感数据的信息隐藏等。
本文介绍一个简单的 Jackson 注解,实现对某些字段的信息隐藏,即将目标对象中的属性,用对应无实际意义的字符替换。
定义 Jackson 注解
使用 @JacksonAnnotationsInside
,定义一个在字段和方法上的注解类 HideSensitiveInfo
,包含掩码和长度两个方法:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
@JacksonAnnotationsInside
@JsonSerialize(using = HideSensitiveInfoSerializer.class)
public @interface HideSensitiveInfo {
/**
* 掩盖数据的字符串为什么,默认为 *
* @return
*/
String mask() default "*";
/**
* 使用多少个掩盖字符串
* @return
*/
int count() default 5;
}
定义注解对应的序列化类
使用该注解的字段或者方法,序列化使用的类 HideSensitiveInfoSerializer
定义,
序列化类与注解是一对一的关系,注解定义了基础配置信息,序列化类获取对应的属性完成 JSON 序列化的输出过程。
public class HideSensitiveInfoSerializer extends StdSerializer<String> implements ContextualSerializer {
private String mask = "?";
private int count = 1;
/**
* 构造函数:必须提供默认构造函数,调用父类的构造函数,且提供一个 T 的类型
*/
public HideSensitiveInfoSerializer() {
super(String.class);
}
/**
* 有参构造函数,第一步必须调用默认构造函数
* @param mask
* @param count
*/
public HideSensitiveInfoSerializer(String mask, int count) {
this();
this.mask = mask;
this.count = count;
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
String mask = "?";
int count = 1;
HideSensitiveInfo anno = null;
if(beanProperty != null) {
anno = beanProperty.getAnnotation(HideSensitiveInfo.class);
}
if (anno !=null ) {
mask = anno.mask();
count = anno.count();
}
return new HideSensitiveInfoSerializer(mask,count);
}
@Override
public void serialize(String s, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
String content = "";
for (int i=0;i<count;i++) {
content += mask;
}
jsonGenerator.writeString(content);
}
}
序列化具有 @HideSensitiveInfo
注解的字段时,简单的用掩码字符拼成一个制定长度的字符串即可。
Java 实体引用注解
定义一个 Java 实体,对需要脱敏的数据使用 @HideSensitiveInfo
注解:
Data
public class MyData {
@HideSensitiveInfo(mask="-",count = 7)
private String telephone;
@HideSensitiveInfo(mask="*",count = 3)
private String name;
public MyData(String telephone,String name) {
this.telephone = telephone;
this.name = name;
}
}
测试 Controller 类
@RestController
@RequestMapping("/test")
public class MyTestJson {
@ResponseBody
@RequestMapping("/hello")
public MyData hello() {
return new MyData("13220045018","10");
}
}
访问该接口,得到隐藏后的信息:
启示录
Java 的注解相比类传递信息更灵活,一行注解就可以额外设置配置信息,省却了类的 new
及属性设置动作。但是注解一般不能单独使用,必须绑定到其他使用它的类上完成对应的功能。
以上是关于自定义一个 Jackson 转换注解完成敏感数据的隐藏的主要内容,如果未能解决你的问题,请参考以下文章