介绍
- 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<String> 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<String, String> {
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<DemoRespDTO> 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