Springboot整合Hutool自定義注解實(shí)現(xiàn)數(shù)據(jù)脫敏
一、前言
我們?cè)陧?xiàng)目中會(huì)處理敏感數(shù)據(jù)(如手機(jī)號(hào)、身份證號(hào)、姓名、地址等)時(shí),通常需要對(duì)這些數(shù)據(jù)進(jìn)行脫敏,以確保數(shù)據(jù)隱私和安全。
我們本次使用 Hutool 庫(kù)來(lái)輕松實(shí)現(xiàn)數(shù)據(jù)脫敏,如果項(xiàng)目中不讓使用,可以自己防著hutool來(lái)寫一些工具類。
本次使用Springboot整合Hutool來(lái)自定義注解實(shí)現(xiàn)數(shù)據(jù)脫敏!
二、什么是數(shù)據(jù)脫敏
數(shù)據(jù)脫敏(Data Masking),也稱為數(shù)據(jù)遮蔽或數(shù)據(jù)隱藏,是一種數(shù)據(jù)保護(hù)技術(shù),用于處理和存儲(chǔ)敏感數(shù)據(jù)時(shí),以減少或消除數(shù)據(jù)中的敏感信息,從而保護(hù)數(shù)據(jù)的隱私和安全。數(shù)據(jù)脫敏的主要目的是在保持?jǐn)?shù)據(jù)可用性的同時(shí),減少數(shù)據(jù)泄露和濫用的風(fēng)險(xiǎn)。
「數(shù)據(jù)脫敏一般指數(shù)據(jù)庫(kù)正常存儲(chǔ),返回前端時(shí)進(jìn)行數(shù)據(jù)庫(kù)處理!」
三、Hutool簡(jiǎn)介
Hutool是一個(gè)小而全的Java工具類庫(kù),通過(guò)靜態(tài)方法封裝,降低相關(guān)API的學(xué)習(xí)成本,提高工作效率,使Java擁有函數(shù)式語(yǔ)言般的優(yōu)雅,讓Java語(yǔ)言也可以“甜甜的”。
Hutool是項(xiàng)目中“util”包友好的替代,它節(jié)省了開發(fā)人員對(duì)項(xiàng)目中公用類和公用工具方法的封裝時(shí)間,使開發(fā)專注于業(yè)務(wù),同時(shí)可以最大限度的避免封裝不完善帶來(lái)的bug。
雖然Hutool可能會(huì)有一些bug,比起小編寫的還是強(qiáng)上不少的,所以選定它來(lái)!
現(xiàn)在最新版為:5.8.16,我們直接使用最新的,bug會(huì)少一些,功能會(huì)完善一些!
支持的脫敏規(guī)則:
- 用戶id
- 中文姓名
- 身份證號(hào)
- 座機(jī)號(hào)
- 手機(jī)號(hào)
- 地址
- 電子郵件
- 密碼
- 中國(guó)大陸車牌,包含普通車輛、新能源車輛
- 銀行卡
四、實(shí)戰(zhàn)整合
1、導(dǎo)入依賴
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.16</version>
</dependency>
2、自定義注解
@JsonSerialize(using = SensitiveInfoSerializer.class)用于指定在序列化時(shí)應(yīng)該使用哪個(gè)自定義序列化器類
「需要和下面的注解搭配使用SensitiveInfoSerializer我們自定義的序列化器才會(huì)生效」
@JacksonAnnotationsInside 主要用于標(biāo)記其他自定義注解,這意味著你可以在一個(gè) Jackson 注解內(nèi)部使用其他自定義注解,以組合各種注解來(lái)實(shí)現(xiàn)更復(fù)雜的序列化和反序列化邏輯。
/**
* @author wangzhenjun
* @date 2023/9/11 14:15
*/
@JacksonAnnotationsInside
@JsonSerialize(using = SensitiveInfoSerializer.class)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Desensitization {
DesensitizationType type() default DesensitizationType.DEFAULT;
/**
* 前置不需要打碼的長(zhǎng)度
*/
int prefixLen() default 0;
/**
* 后置不需要打碼的長(zhǎng)度
*/
int suffixLen() default 0;
/**
* 遮罩字符
*/
String maskingChar() default "*";
}
3、支持類型枚舉
/**
* @author wangzhenjun
* @date 2023/9/11 14:43
*/
public enum DesensitizationType {
// 自定義規(guī)則
CUSTOMIZE_RULE,
// 默認(rèn)的
DEFAULT,
//用戶id
USER_ID,
//中文名
CHINESE_NAME,
//身份證號(hào)
ID_CARD,
//座機(jī)號(hào)
FIXED_PHONE,
//手機(jī)號(hào)
MOBILE_PHONE,
//地址
ADDRESS,
//電子郵件
EMAIL,
//密碼
PASSWORD,
//中國(guó)大陸車牌,包含普通車輛、新能源車輛
CAR_LICENSE,
//銀行卡
BANK_CARD
}
4、自定義序列化器
關(guān)于自定義的規(guī)則,大家可以根據(jù)自己的需求來(lái)寫工具類,我這里簡(jiǎn)單使用Hutool的工具來(lái)了!
StrUtil.replace(value, prefixLen, suffixLen, maskingChar)StrUtil.hide(value, prefixLen, suffixLen)
createContextual 方法首先在序列化過(guò)程開始時(shí)被調(diào)用,返回的序列化器實(shí)例將用于后續(xù)的序列化過(guò)程。
serialize 方法負(fù)責(zé)實(shí)際的序列化邏輯,將字段的值轉(zhuǎn)換為JSON,并可以在其中執(zhí)行自定義的脫敏邏輯。
/**
* 數(shù)據(jù)脫敏序列化器
*
* @author wangzhenjun
* @date 2023/9/11 14:16
*/
public class SensitiveInfoSerializer extends JsonSerializer<String> implements ContextualSerializer {
private boolean useMasking = false;
private DesensitizationType type;
private int prefixLen;
private int suffixLen;
private String maskingChar;
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
if (useMasking && value != null) {
switch (type) {
case MOBILE_PHONE:
gen.writeString(DesensitizedUtil.mobilePhone(value));
break;
case ID_CARD:
gen.writeString(DesensitizedUtil.idCardNum(value, prefixLen, suffixLen));
break;
case CUSTOMIZE_RULE:
// gen.writeString(StrUtil.replace(value, prefixLen, suffixLen, maskingChar));
gen.writeString(StrUtil.hide(value, prefixLen, suffixLen));
break;
case CHINESE_NAME:
gen.writeString(DesensitizedUtil.chineseName(value));
break;
case DEFAULT:
gen.writeString(value);
default:
gen.writeString(value);
}
} else {
gen.writeObject(value);
}
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) {
if (property != null) {
Desensitization desensitization = property.getAnnotation(Desensitization.class);
if (desensitization != null) {
this.type = desensitization.type();
this.prefixLen = desensitization.prefixLen();
this.suffixLen = desensitization.suffixLen();
this.maskingChar = desensitization.maskingChar();
useMasking = true;
}
}
return this;
}
}
5、實(shí)體類應(yīng)用
/**
* @author wangzhenjun
* @date 2023/9/12 9:15
*/
@Data
public class User {
@Desensitization(type = DesensitizationType.ID_CARD,prefixLen = 6,suffixLen = 16)
private String cardId;
@Desensitization(type = DesensitizationType.CHINESE_NAME)
private String name;
@Desensitization(type = DesensitizationType.MOBILE_PHONE)
private String phone;
@Desensitization(type = DesensitizationType.CUSTOMIZE_RULE,prefixLen = 3,suffixLen = 6)
private String info;
}
6、測(cè)試
@GetMapping("/getUser")
public Result getUser(){
User user = new User();
user.setCardId("372911111111111111");
user.setPhone("15822229999");
user.setName("趙飛燕");
user.setInfo("這是機(jī)密文件,該打碼打碼");
return Result.success(user);
}
完美脫敏,此次應(yīng)該有掌聲!
五、總結(jié)
本文通過(guò)Spring Boot與Hutool庫(kù)的結(jié)合使用自定義注解,提供了一個(gè)簡(jiǎn)單而強(qiáng)大的方式來(lái)實(shí)現(xiàn)數(shù)據(jù)脫敏。希望能幫助到你,成功地實(shí)現(xiàn)數(shù)據(jù)脫敏功能,并提高應(yīng)用程序的安全性。
本次例子脫敏選項(xiàng)沒(méi)有演示全,大家可以自行補(bǔ)充完成,成為你們需要的數(shù)據(jù)脫敏策略,從而完美的處理用戶數(shù)據(jù)脫敏問(wèn)題!
可以試著使用AOP來(lái)完成脫敏,有興趣的可以試一下哈!