目录

[TOC]

引入依赖

Hutool 5.x支持JDK8+, 如果你的项目使用JDK7,请使用Hutool 4.x版本。本文使用的数据脱敏工具类只有在5.6+版本以上才提供。

1
2
3
4
5
6
<!--hutool工具类-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.16</version>
</dependency>

Hutool支持的脱敏数据类型

  • 用户id

  • 中文名

  • 身份证号

  • 座机号

  • 手机号

  • 地址

  • 电子邮件

  • 密码

  • 中国大陆车牌,包含普通车辆、新能源车辆

  • 银行卡

  • IPv4地址

  • IPv6地址

  • 定义了一个first_mask的规则,只显示第一个字符。

Hutool数据脱敏实操

创建注解类

在实体类需要脱敏的字段上,使用该注解标注和指定脱敏的类型,数据则会在序列化的时候进行脱敏处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import cn.hutool.core.util.DesensitizedUtil;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.xiaofei.encryption.config.DesensitizationSerialize;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* 数据脱敏使用注解,在需要脱敏的字段上添加该注解,然后配合自定义序列化,将数据进行脱敏
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = DesensitizationSerialize.class)
public @interface Desensitization {
/**
* 脱敏数据类型
*/
DesensitizedUtil.DesensitizedType type() default DesensitizedUtil.DesensitizedType.FIRST_MASK;
}

创建序列化配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import cn.hutool.core.util.DesensitizedUtil;
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.xiaofei.encryption.annotation.Desensitization;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.util.Objects;

/**
* 数据脱敏自定义序列化类
*/
@AllArgsConstructor
@NoArgsConstructor
public class DesensitizationSerialize extends JsonSerializer<String> implements ContextualSerializer {

private DesensitizedUtil.DesensitizedType type;

@Override
public void serialize(String str, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
if (!StringUtils.isEmpty(str)) {

// 匹配不同脱敏类型,对数据做不同的脱敏操作
switch (type) {
case USER_ID:
str = String.valueOf(DesensitizedUtil.userId());
break;
case CHINESE_NAME:
str = DesensitizedUtil.chineseName(str);
break;
case ID_CARD:
str = DesensitizedUtil.idCardNum(str, 1, 2);
break;
case FIXED_PHONE:
str = DesensitizedUtil.fixedPhone(str);
break;
case MOBILE_PHONE:
str = DesensitizedUtil.mobilePhone(str);
break;
case ADDRESS:
str = DesensitizedUtil.address(str, 8);
break;
case EMAIL:
str = DesensitizedUtil.email(str);
break;
case PASSWORD:
str = DesensitizedUtil.password(str);
break;
case CAR_LICENSE:
str = DesensitizedUtil.carLicense(str);
break;
case BANK_CARD:
str = DesensitizedUtil.bankCard(str);
break;
case IPV4:
str = DesensitizedUtil.ipv4(str);
break;
case IPV6:
str = DesensitizedUtil.ipv6(str);
break;
case FIRST_MASK:
str = DesensitizedUtil.firstMask(str);
break;
default:
}
jsonGenerator.writeString(str);
}
}

@Override
public 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);
// 为null
if (desensitization == null) {
desensitization = beanProperty.getContextAnnotation(Desensitization.class);
}
// 不为null
if (desensitization != null) {
// 创建定义的序列化类的实例并且返回,入参为注解定义的type,开始位置,结束位置。
return new DesensitizationSerialize(desensitization.type());
}
}

return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
}
return serializerProvider.findNullValueSerializer(null);
}
}

实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import cn.hutool.core.util.DesensitizedUtil;
import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.xiaofei.encryption.annotation.Desensitization;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.io.Serializable;

/**
* 用户
*/
@Data
@EqualsAndHashCode(callSuper = true)
@ApiModel("用户表")
@TableName(value = "user")
public class UserEntity extends BaseEntity implements Serializable {

@ApiModelProperty("密码,加密存储")
@Desensitization(type = DesensitizedUtil.DesensitizedType.PASSWORD)
private String password;

@ApiModelProperty("手机号")
@Desensitization(type = DesensitizedUtil.DesensitizedType.MOBILE_PHONE)
private String phone;
}

结果

通过图片可以查看到,返回的数据已经进行脱敏处理了,后续只需要在实体类上使用自定义注解Desensitization,然后再指定需要脱敏的类型,即可对数据针对性的脱敏

image-20230815224500111