SpringBoot 实现数据脱敏
- 前言
- Hutool 实现数据脱敏
- 引入依赖
- 脱敏工具类
- 代码实现
- 使用注解的方式
- 定义枚举
- 自定义序列化类
- 定义注解
- 测试
前言
数据脱敏是指对某些敏感信息通过脱敏规则进行数据的变形,实现敏感隐私数据的可靠保护。
数据脱敏常用规则有替换、重排、加密、截断、掩码
- 替换:用其他字符或者符号替换原始数据中的字符或者符号,例如将手机号码中间四位替换为星号。
- 重排:将原始数据中的字符或者符号重新排列,例如将身份证号码中的数字重新排列。
- 加密:使用加密算法对原始数据进行加密,例如使用AES算法对银行卡号进行加密。
- 截断:将原始数据中的一部分截取掉,例如只保留姓名的首字母。
- 掩码:使用特定符号或者字符掩盖原始数据中的一部分,例如使用星号掩盖信用卡号码中的一部分数字。
Hutool 实现数据脱敏
hutool ——一个 Java 基础工具类,对文件、流、加密解密、转码、正则、线程、XML等JDK方法进行封装,组成各种 Util 工具类
官方文档:简介 | Hutool
引入依赖
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.16</version>
</dependency>
脱敏工具类
hutool 使用信息脱敏工具——DesensitizedUtil 实现脱敏操作
现阶段支持的脱敏数据类型包括:
- 用户id
- 中文姓名
- 身份证号
- 座机号
- 手机号
- 地址
- 电子邮件
- 密码
- 中国大陆车牌,包含普通车辆、新能源车辆
- 银行卡
自定义隐藏可以使用StrUtil.hide
方法完成
代码实现
public class HutoolDesensitized {public static void main(String[] args) {String phone = "15888888888";System.out.println(DesensitizedUtil.mobilePhone(phone)); // 158****8888String idCard = "490508200001010001";System.out.println(DesensitizedUtil.idCardNum(idCard,4,4)); // 4905**********0001String password = "dddd3343ssxx";System.out.println(DesensitizedUtil.password(password)); // ************ 对于密码则只保留位数String bankCard = "8845600134008139446";System.out.println(DesensitizedUtil.bankCard(bankCard)); // 8845 **** **** *** 9446}}
使用注解的方式
使用 SpringBoot 自带的 jackson 自定义序列化实现,在 json 进行序列化返回时,实现脱敏
定义枚举
public enum DesensitizationTypeEnum {// 自定义CUSTOM_RULE,// 用户idUSER_ID,// 中文名CHINESE_NAME,// 身份证号ID_CARD,// 座机号FIXED_PHONE,// 手机号MOBILE_PHONE,// 地址ADDRESS,// 电子邮件EMAIL,// 密码PASSWORD,// 车牌CAR_LICENSE,//银行卡BANK_CARD
}
自定义序列化类
继承JsonSerializer,实现 ContextualSerializer 接口
@AllArgsConstructor
@NoArgsConstructor
public class DesensitizationSerialize extends JsonSerializer<String> implements ContextualSerializer {private DesensitizationTypeEnum type;private Integer startInclude;private Integer endExclude;@Overridepublic void serialize(String str, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {switch (type) {// 自定义类型脱敏case CUSTOM_RULE:jsonGenerator.writeString(CharSequenceUtil.hide(str, startInclude, endExclude));break;// 用户名脱敏case USER_ID:jsonGenerator.writeString(String.valueOf(DesensitizedUtil.userId()));break;// 中文姓名脱敏case CHINESE_NAME:jsonGenerator.writeString(DesensitizedUtil.chineseName(String.valueOf(str)));break;// 身份证脱敏case ID_CARD:jsonGenerator.writeString(DesensitizedUtil.idCardNum(String.valueOf(str), 4, 4));break;// 固定电话脱敏case FIXED_PHONE:jsonGenerator.writeString(DesensitizedUtil.fixedPhone(String.valueOf(str)));break;// 手机号脱敏case MOBILE_PHONE:jsonGenerator.writeString(DesensitizedUtil.mobilePhone(String.valueOf(str)));break;// 地址脱敏case ADDRESS:jsonGenerator.writeString(DesensitizedUtil.address(String.valueOf(str), 8));break;// 邮箱脱敏case EMAIL:jsonGenerator.writeString(DesensitizedUtil.email(String.valueOf(str)));break;// 密码脱敏case PASSWORD:jsonGenerator.writeString(DesensitizedUtil.password(String.valueOf(str)));break;// 中国车牌脱敏case CAR_LICENSE:jsonGenerator.writeString(DesensitizedUtil.carLicense(String.valueOf(str)));break;// 银行卡脱敏case BANK_CARD:jsonGenerator.writeString(DesensitizedUtil.bankCard(String.valueOf(str)));break;default:}}@Overridepublic JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {if (beanProperty != null) {// 判断数据类型是否为String类型if (Objects.equals(beanProperty.getType().getRawClass(), String.class)) {// 获取定义的注解Desensitization desensitization = beanProperty.getAnnotation(Desensitization.class);// 为nullif (desensitization == null) {desensitization = beanProperty.getContextAnnotation(Desensitization.class);}// 不为nullif (desensitization != null) {// 创建定义的序列化类的实例并且返回,入参为注解定义的type,开始位置,结束位置。return new DesensitizationSerialize(desensitization.type(), desensitization.startInclude(),desensitization.endExclude());}}return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);}return serializerProvider.findNullValueSerializer(null);}
}
定义注解
@JsonSerialize
定义 json 序列化器
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = DesensitizationSerialize.class)
public @interface Desensitization {/*** 脱敏数据类型,在 CUSTOM_RULE 的时候,startInclude 和 endExclude 生效*/DesensitizationTypeEnum type() default DesensitizationTypeEnum.CUSTOM_RULE;/*** 脱敏开始位置(包含)*/int startInclude() default 0;/*** 脱敏结束位置(不包含)*/int endExclude() default 0;
}
测试
定义一个测试类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class TestUser {@Desensitization(type = DesensitizationTypeEnum.MOBILE_PHONE)private String phone;@Desensitization(type = DesensitizationTypeEnum.EMAIL)private String email;@Desensitization(type = DesensitizationTypeEnum.CUSTOM_RULE,startInclude = 3, endExclude = 9)private String customEntity;
}
测试接口
@RestController
@RequestMapping
public class TestController {@GetMapping("/test")public TestUser testDesensitization() {TestUser testUser = new TestUser();testUser.setPhone("15888888888");testUser.setEmail("dadfd_333@163.com");testUser.setCustomEntity("dfkdjf3434__495kdjf@@");return testUser;}
}
返回数据