介绍
- SpringBoot实现数据脱敏响应请求
- 有时,由于业务需要,敏感数据返回给第三方时,需要进行隐藏处理,但是如果一个字段一个字段的进行硬编码处理的话,不仅增加了工作量,而且后期需求变动的时候,更加是地狱般的工作量变更。下面将介绍一种高效便捷的处理方法。
- 下面,通过身份证,姓名,密码,手机号等等示例去演示脱敏的流程
原理
- 项目使用的是SpringBoot进行搭建,所以使用内置的序列化工具jackson进行序列化
- 通过实现com.fasterxml.jackson.databind.JsonSerializer进行自定义序列化
- 通过重写com.fasterxml.jackson.databind.ser.ContextualSerializer.createContextual获取自定义注解的信息
实现
- 添加自定义序列化注解
- 注意,必需添加@JacksonAnnotationsInside和@JsonSerialize(using = MyJsonSerializer.class)注解,否则序列化无法生效
@JacksonAnnotationsInside
@JsonSerialize(using = MyJsonSerializer.class)
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@documented
@Inherited
public @interface CustomSerializer {
Class extends baseRule> value() default DefaultRule.class;
String pattern() default "";
String format() default "";
}
- 添加自定义序列化实现类
@Slf4j
public class MyJsonSerializer extends JsonSerializer implements ContextualSerializer {
private baseRule rule;
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeString(rule.apply(value));
}
@Override
public JsonSerializer> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
//获取对象属性上的自定义注解
CustomSerializer customSerializer = property.getAnnotation(CustomSerializer.class);
if (null != customSerializer) {
try {
//根据注解的配置信息,创建对应脱敏规则处理类
this.rule = customSerializer.value().newInstance();
//如果正则信息不为空,则使用注解上的正则初始化到对应的脱敏规则处理类中
if (isNotBlank(customSerializer.pattern()) && isNotBlank(customSerializer.format())) {
this.rule.setRule(new RuleItem()
.setRegex(customSerializer.pattern())
.setFormat(customSerializer.format()));
}
return this;
} catch (Exception e) {
log.error("json转换处理异常", e);
}
}
return prov.findValueSerializer(property.getType(), property);
}
private boolean isNotBlank(String str) {
return null != str && str.trim().length() > 0;
}
}
- 添加脱敏规则
//脱敏对象
@Data
@Accessors(chain = true)
public class RuleItem {
private String regex;
private String format;
}
//脱敏处理基类
@Data
public abstract class baseRule implements Function {
private RuleItem rule;
public String apply(String str) {
if (null == str) {
return null;
}
//初始化脱敏规则
initRule();
if (null == rule || null == rule.getRegex() || null == rule.getFormat()) {
return str;
}
//正则替换
return str.replaceAll(rule.getRegex(), rule.getFormat());
}
abstract void initRule();
}
//默认脱敏处理类
public class DefaultRule extends baseRule {
@Override
void initRule() {
}
}
//身份证号脱敏处理类
public class IdCardRule extends baseRule {
@Override
void initRule() {
setRule(new RuleItem()
.setRegex("(\d{6})\d*(\w{4})")
.setFormat("$1********$2"));
}
}
//密码脱敏处理类
public class PasswordRule extends baseRule {
@Override
public String apply(String str) {
return "******";
}
@Override
void initRule() {
}
}
//手机号脱敏处理类
public class PhoneRule extends baseRule {
@Override
void initRule() {
setRule(new RuleItem()
.setRegex("(\d{3})\d*(\d{4})")
.setFormat("$1****$2"));
}
}
//姓名脱敏处理类
public class UserNameRule extends baseRule {
@Override
void initRule() {
setRule(new RuleItem()
.setRegex("\S*(\S)")
.setFormat("**$1"));
}
}
- 测试代码
@RestController
public class DemoController {
@GetMapping(value = "/test")
public Response test() {
DemoRespDTO respDTO = new DemoRespDTO();
respDTO.setUserName("张三");
respDTO.setPhone("18812345678");
respDTO.setIdCard("15030319520807064X");
respDTO.setPassword("asdf12345678");
respDTO.setCustomValue("sfwegewgrergergwefwefwef");
return Response.success(respDTO);
}
}
@NoArgsConstructor
@Data
@Accessors(chain = true)
public class DemoRespDTO implements Serializable {
private static final long serialVersionUID = 1019466745376831818L;
@CustomSerializer(UserNameRule.class)
private String userName;
@CustomSerializer(PhoneRule.class)
private String phone;
@CustomSerializer(IdCardRule.class)
private String idCard;
@CustomSerializer(PasswordRule.class)
private String password;
@CustomSerializer(pattern = "\S{10}(\S*)", format = "**********$1")
private String customValue;
}
- 结果示例
{
"code": 200,
"message": "success",
"data": {
"userName": "**三",
"phone": "188****5678",
"idCard": "150303********064X",
"password": "******",
"customValue": "**********rgergwefwefwef"
}
}
- 码云:https://gitee.com/hweiyu/spring-boot-data-security