SpringBoot使用自定义注解实现返回数据脱敏操作
在实际项目中,对于敏感数据的保护十分重要,数据脱敏又称数据去隐私化或数据变形,是在给定的规则、策略下对敏感数据进行变换、修改的技术机制,能够在很大程度上解决敏感数据在非可信环境中使用的问题。
本文使用自定义注解,在返回数据给前端的时候,根据给定的脱敏规则实现敏感数据脱敏操作,实现过程非常简单,一起来看看吧!
1、引入依赖
<!-- hutool工具类 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.6.7</version>
</dependency>
2、自定义注解 - Desensitize
package com.ltkj.common.annotation;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.ltkj.common.enums.SensitiveStrategy;
import com.ltkj.common.jackson.SensitiveJsonSerializer;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 数据脱敏注解
*
* @author wangl
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside
@JsonSerialize(using = SensitiveJsonSerializer.class)
public @interface Sensitive {
SensitiveStrategy strategy();
}
3、脱敏规则枚举类
package com.ltkj.common.enums;
import cn.hutool.core.util.DesensitizedUtil;
import lombok.AllArgsConstructor;
import java.util.function.Function;
/**
* 脱敏策略
*
* @author wangl
*/
@AllArgsConstructor
public enum SensitiveStrategy {
/**
* 身份证脱敏
*/
ID_CARD(s -> DesensitizedUtil.idCardNum(s, 3, 4)),
/**
* 手机号脱敏
*/
PHONE(DesensitizedUtil::mobilePhone),
/**
* 地址脱敏
*/
ADDRESS(s -> DesensitizedUtil.address(s, 8)),
/**
* 邮箱脱敏
*/
EMAIL(DesensitizedUtil::email),
/**
* 银行卡
*/
BANK_CARD(DesensitizedUtil::bankCard);
//可自行添加其他脱敏策略
private final Function<String, String> desensitizer;
public Function<String, String> desensitizer() {
return desensitizer;
}
}
这其中的脱敏规则全都依赖 hutool 的 DesensitizedUtil 工具类,有其它的脱敏规则可以自定义实现
4、数据脱敏 JSON 序列化工具
package com.ltkj.common.jackson;
import cn.hutool.core.util.ObjectUtil;
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.ltkj.common.annotation.Sensitive;
import com.ltkj.common.core.service.SensitiveService;
import com.ltkj.common.enums.SensitiveStrategy;
import com.ltkj.common.utils.spring.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import java.io.IOException;
import java.util.Objects;
/**
* 数据脱敏json序列化工具
*
* @author wangl
*/
@Slf4j
public class SensitiveJsonSerializer extends JsonSerializer<String> implements ContextualSerializer {
private SensitiveStrategy strategy;
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
try {
SensitiveService sensitiveService = SpringUtils.getBean(SensitiveService.class);
if (ObjectUtil.isNotNull(sensitiveService) && sensitiveService.isSensitive()) {
gen.writeString(strategy.desensitizer().apply(value));
} else {
gen.writeString(value);
}
} catch (BeansException e) {
log.error("脱敏实现不存在, 采用默认处理 => {}", e.getMessage());
gen.writeString(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);
}
}
SpringBoot 中默认使用 jackson 作为 JSON 序列化工具,我们获取到自定义的脱敏注解(@Sensitive ),就对该数据实现我们的脱敏操作,就完成了我们的敏感数据脱敏操作。
import com.ltkj.common.core.service.SensitiveService;
import com.ltkj.common.helper.LoginHelper;
import org.springframework.stereotype.Service;
/**
* 脱敏服务
* 默认管理员不过滤
* 需自行根据业务重写实现
*
* @author wangl脱敏服务
* @date 2023-10-10
*/
@Service
public class SysSensitiveServiceImpl implements SensitiveService {
/**
* 动态判断是否脱敏
* 默认管理员不过滤
*/
@Override
public boolean isSensitive() {
return !LoginHelper.isAdmin();
}
}
5 测试结果
访问接口:
http://localhost:8090/test
得到数据:
可以看出,对应的敏感数据被进行脱敏了,证明我们的脱敏注解生效了