springboot+jackson+Hutool 脱敏注解
1 实现
脱敏注解:
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.test.desensitize.DesensitizeJsonSerializer;
import com.test.desensitize.enums.DesensitizeStrategy;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* <pre>
* 脱敏注解,标注在属性上
* </pre>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside
@JsonSerialize(using = DesensitizeJsonSerializer.class)
public @interface Desensitize {
/**
* 脱敏策略
*/
DesensitizeStrategy strategy();
}
脱敏策略枚举类:
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.util.Function;
/**
* <pre>
* 脱敏策略枚举类,针对不同的数据定制特定的脱敏策略
* </pre>
*/
public enum DesensitizeStrategy {
/**
* 用户名,只显示第一个字,例如: 张三->张* 张三丰->张**
*/
USERNAME(s -> StrUtil.isBlank(s) ? "" : StrUtil.hide(s, 1, s.length())),
/**
* 身份证,显示前四位和后两位,例如:1002************23
*/
ID_CARD(s -> StrUtil.isBlank(s) ? "" : StrUtil.hide(s, 4, s.length() - 2)),
/**
* 手机号,显示前四位和后四位,例如:
*/
PHONE(s -> StrUtil.isBlank(s) ? "" : StrUtil.hide(s, 3, s.length() - 4)),
/**
* 密码,全部隐藏,只显示位数
*/
PASSWORD(s -> StrUtil.isBlank(s) ? "" : StrUtil.repeat('*', s.length())),
/**
* 邮箱,隐藏第一位和@中间内容,例如:1*********@qq.com
*/
EMAIL(s -> {
if (StrUtil.isBlank(s)) {
return "";
} else {
int index = StrUtil.indexOf(s, '@');
return index <= 1 ? s : StrUtil.hide(s, 1, index);
}
});
private final Function<String, String> desensitize;
DesensitizeStrategy(Function<String, String> desensitize) {
this.desensitize = desensitize;
}
public Function<String, String> desensitize() {
return desensitize;
}
}
核心代码:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.test.desensitize.annotation.Desensitize;
import com.test.desensitize.enums.DesensitizeStrategy;
import java.io.IOException;
import java.util.Objects;
/**
* <pre>
* 序列化注解自定义实现
* JsonSerializer<String>:指定String类型,serialize()方法用于将修改后的数据载入
* Jackson使用ContextualSerializer在序列化时获取字段注解的属性
* </pre>
*/
public class DesensitizeJsonSerializer extends JsonSerializer<String> implements ContextualSerializer {
private DesensitizeStrategy strategy;
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeString(strategy.desensitize().apply(value));
}
/**
* 获取属性上的注解属性
*/
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
Desensitize annotation = property.getAnnotation(Desensitize.class);
// 只针对String类型属性进行脱敏
if (Objects.nonNull(annotation)&&Objects.equals(String.class, property.getType().getRawClass())) {
this.strategy = annotation.strategy();
return this;
}
return prov.findValueSerializer(property.getType(), property);
}
}
2 使用场景及描述
使用场景:需要脱敏数据的时候
以下是目前提供的几种类型的脱敏策略及说明,使用时可根据脱敏策略或脱敏效果,进行选择。
脱敏策略 | 脱敏效果 | 示例 |
---|---|---|
用户名(姓名) | 只显示第一个字 | 张三–>张* 张三丰–>张** |
身份证号 | 显示前四位和后两位 | 1002************23 |
手机号 | 显示前三位和后四位 | 139****2312 |
密码 | 全部隐藏,只显示位数 | ****** |
邮箱 | 隐藏第一位和@中间内容 | 1*********@qq.com |
3 使用方法
3.1 添加注解@Desensitize
在需要进行脱敏的字段上添加@Desensitize注解,并选择具体的脱敏策略。示例如下:
@Data
public class PersonVo {
/**
* 真实姓名 只显示第一个字,例如: 张三->张* 张三丰->张**
*/
@Desensitize(strategy = DesensitizeStrategy.USERNAME)
private String realName;
/**
* 密码 全部隐藏,只显示位数
*/
@Desensitize(strategy = DesensitizeStrategy.PASSWORD)
private String password;
/**
* 电话号码 显示前三位和后四位,例如:139****2342
*/
@Desensitize(strategy = DesensitizeStrategy.PHONE)
private String phoneNumber;
/**
* 身份证号码 显示前四位和后两位,例如:4102************23
*/
@Desensitize(strategy = DesensitizeStrategy.ID_CARD)
private String idCard;
/**
* 邮箱 隐藏第一位和@中间内容,例如:1*********@qq.com
*/
@Desensitize(strategy = DesensitizeStrategy.EMAIL)
private String email;
}
3.2 脱敏结果
脱敏前数据:
{
"realName": "张三",
"password": "123456789",
"phoneNumber": "13901010234",
"idCard": "100103199603282410",
"email": "1234567.qq.com"
}
脱敏后数据:
{
"realName": "张*",
"password": "*********",
"phoneNumber": "139****0234",
"idCard": "1001************10",
"email": "1******@qq.com"
}