数据动态脱敏
业务背景
某些敏感数据不能展示在前台
解决方案
增加注解Sensitive
,设置对应的脱敏策略,使用自定义的序列化器
@Retention ( RetentionPolicy . RUNTIME )
@Target ( ElementType . FIELD )
@JacksonAnnotationsInside
@JsonSerialize ( using = SensitiveJsonSerializer . class )
public @interface Sensitive {
SensitiveStrategy strategy ( ) ;
}
添加对应的脱敏策略
public enum SensitiveStrategy {
USERNAME ( s -> s. replaceAll ( "(\\S)\\S(\\S*)" , "$1*$2" ) ) ,
ID_CARD ( s -> s. replaceAll ( "(\\d{4})\\d{10}(\\w{4})" , "$1****$2" ) ) ,
PHONE ( s -> s. replaceAll ( "(\\d{3})\\d{4}(\\d{4})" , "$1****$2" ) ) ,
ADDRESS ( s -> s. replaceAll ( "(\\S{3})\\S{2}(\\S*)\\S{2}" , "$1****$2****" ) ) ;
private final Function < String , String > desensitizer;
SensitiveStrategy ( Function < String , String > desensitizer) {
this . desensitizer = desensitizer;
}
public Function < String , String > desensitizer ( ) {
return desensitizer;
}
}
添加自定义序列化器
public class SensitiveJsonSerializer extends JsonSerializer < String > implements ContextualSerializer {
private SensitiveStrategy strategy;
@Override
public void serialize ( String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen. writeString ( strategy. desensitizer ( ) . apply ( value) ) ;
}
@Override
public JsonSerializer < ? > createContextual ( SerializerProvider prov, BeanProperty property) throws JsonMappingException {
Sensitive annotation = property. getAnnotation ( Sensitive . class ) ;
if ( Objects . nonNull ( annotation) && Objects . equals ( String . class , property. getType ( ) . getRawClass ( ) ) ) {
this . strategy = annotation. strategy ( ) ;
return this ;
}
return prov. findValueSerializer ( property. getType ( ) , property) ;
}
}
在想要数据脱敏的实体类上添加注解
@Data
public class Person {
@Sensitive ( strategy = SensitiveStrategy . USERNAME )
private String realName;
@Sensitive ( strategy = SensitiveStrategy . ADDRESS )
private String address;
@Sensitive ( strategy = SensitiveStrategy . PHONE )
private String phoneNumber;
@Sensitive ( strategy = SensitiveStrategy . ID_CARD )
private String idCard;
}
效果
Person person = new Person( ) ;
person.setRealName( "张三" ) ;
person.setAddress( "上海市天天向上路391号" ) ;
person.setIdCard( "112233445500001111" ) ;
person.setPhoneNumber( "15611114444" ) ;
{ "realName" : "张*" ,"address" : "上海市****向上路39****" ,"phoneNumber" : "156****4444" ,"idCard" : "1122****1111" }
源码参考
应用仓库:https://gitee.com/charles_ruan/SpringBootDemo(2022/demo-tools)