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;@Overridepublic 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);}}@Overridepublic 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 {/*** 动态判断是否脱敏* 默认管理员不过滤*/@Overridepublic boolean isSensitive() {return !LoginHelper.isAdmin();}}
5 测试结果
访问接口:
http://localhost:8090/test
得到数据:
可以看出,对应的敏感数据被进行脱敏了,证明我们的脱敏注解生效了