以下是使用自定义Json注解实现输出日志字段脱敏的完整攻略。
什么是Json注解
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于阅读和编写。在Java应用程序中,我们通常使用Jackson或者Gson等库将Java对象序列化为JSON格式。而Json注解则是在Java对象中添加特定标记以控制序列化和反序列化过程的一种方式。
为什么需要Json注解
在某些情况下,我们需要对输出的字段进行脱敏,比如手机号、身份证号等敏感信息。如果我们直接将对象序列化为JSON格式输出,这些敏感信息就暴露给了外界。因此,有必要使用Json注解对输出的字段进行脱敏。
如何使用自定义Json注解实现输出日志字段脱敏
- 定义自定义注解
我们先定义一个自定义注解 @SensitiveProperty
,用于标记需要脱敏的字段。
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SensitiveProperty {
}
- 定义Jackson的自定义序列化程序
我们定义一个SensitivePropertySerializer
用于实现自定义的序列化逻辑。该序列化程序会在序列化时遍历Java对象的所有属性,并判断哪些属性被标记为@SensitiveProperty,将其进行脱敏处理。
public class SensitivePropertySerializer extends JsonSerializer<Object> {
private static final String SENSITIVE_MASK = "******";
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeStartObject();
PropertyFilter filter = new SimpleBeanPropertyFilter() {
@Override
public void serializeAsField(Object pojo, JsonGenerator jgen, SerializerProvider provider, PropertyWriter writer) throws Exception {
if (!writer.isFiltered()) {
if (writer.getAnnotation(SensitiveProperty.class) != null) {
jgen.writeStringField(writer.getName(), SENSITIVE_MASK);
} else {
writer.serializeAsField(pojo, jgen, provider);
}
}
}
};
ObjectMapper mapper = new ObjectMapper();
mapper.setFilterProvider(new SimpleFilterProvider().addFilter("myFilter", filter));
mapper.writerWithDefaultPrettyPrinter().writeValue(gen, value);
gen.writeEndObject();
}
}
- 定义Java对象
在Java对象中添加自定义注解@SensitiveProperty
来标记需要脱敏的属性。
public class User {
private int id;
private String name;
private String phone;
private String address;
@SensitiveProperty
private String idCard;
// getter和setter方法省略
}
- 序列化Java对象
我们使用Jackson将Java对象序列化为JSON格式,并实现脱敏。
public class Main {
public static void main(String[] args) {
User user = new User();
user.setId(1);
user.setName("张三");
user.setPhone("18312345678");
user.setAddress("北京市海淀区");
user.setIdCard("110101199001011234");
SimpleFilterProvider filterProvider = new SimpleFilterProvider();
filterProvider.addFilter("myFilter", SimpleBeanPropertyFilter.filterOutAllExcept("id", "name", "phone", "address", "idCard"));
ObjectMapper mapper = new ObjectMapper();
mapper.setFilterProvider(filterProvider);
try {
String jsonString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(user);
System.out.println(jsonString);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
}
执行以上代码,控制台输出的JSON字符串如下所示:
{
"id" : 1,
"name" : "张三",
"phone" : "18312345678",
"address" : "北京市海淀区",
"idCard" : "******"
}
- 使用自定义注解实现多种脱敏方式
除了像上面的例子一样使用固定的脱敏字符串,有时我们可能需要根据需求进行不同方式的脱敏。此时,我们可以在@SensitiveProperty注解中添加一个脱敏类型的参数。
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SensitiveProperty {
String type() default "default";
}
在序列化程序中判断注解中的脱敏类型字段,进行不同的脱敏方式。
public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
// ...
String rawValue = String.valueOf(propertyValue);
if ("default".equals(sensitiveType)) {
jgen.writeStringField(name, SENSITIVE_MASK);
} else if ("name".equals(sensitiveType)) {
jgen.writeStringField(name, rawValue.substring(0, 1) + SENSITIVE_MASK);
} else if ("phone".equals(sensitiveType)) {
jgen.writeStringField(name, rawValue.substring(0, 3) + SENSITIVE_MASK + rawValue.substring(7));
} else if ("idCard".equals(sensitiveType)) {
jgen.writeStringField(name, rawValue.substring(0, 4) + SENSITIVE_MASK + rawValue.substring(14));
} else {
writer.serializeAsField(pojo, jgen, provider);
}
}
我们可以使用上面定义的注解@SensitiveProperty来标记需要脱敏的字段以及不同的脱敏方式。
public class User {
private int id;
@SensitiveProperty(type = "name")
private String name;
@SensitiveProperty(type = "phone")
private String phone;
private String address;
@SensitiveProperty(type = "idCard")
private String idCard;
// getter和setter方法省略
}
执行以上代码,输出的JSON字符串如下所示:
{
"id" : 1,
"name" : "张******",
"phone" : "183****5678",
"address" : "北京市海淀区",
"idCard" : "1101******1234"
}
这样,我们利用自定义注解@SensitiveProperty
和Jackson的自定义序列化程序就实现了输出日志字段脱敏的功能。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:使用自定义Json注解实现输出日志字段脱敏 - Python技术站