- 一.Hutool庫
- 二.配合JackSon透過註解方式實現脫敏
根據搜尋結果,MyBatis-Flex、Hutool庫和Jackson是三種常用的脫敏方式,它們各有特點和應用場景。以下是它們的比較:
-
MyBatis-Flex:
- 提供了
@ColumnMask()
註解,並內建了9種脫敏規則,如手機號、固定電話、身份證號、車牌號、地址、郵件、密碼和銀行卡號脫敏。 - 支援自定義脫敏規則,透過
MaskManager
註冊新的脫敏規則。 - 適用於ORM場景,特別是在資料訪問層對查詢結果進行脫敏處理。
- 提供了
-
Hutool庫:
- 提供了
DesensitizedUtil
工具類,支援多種脫敏資料型別,包括使用者id、中文姓名、身份證號、座機號、手機號、地址、電子郵件、密碼、中國大陸車牌和銀行卡。 - 透過靜態方法一行程式碼實現脫敏,如
DesensitizedUtil.mobilePhone()
、DesensitizedUtil.bankCard()
等。 - 適用於需要快速、靈活進行資料脫敏的場景,特別是在Java程式碼中直接處理資料脫敏。
- 提供了
-
Jackson:
- 透過自定義序列化器和註解方式實現脫敏,可以在JSON序列化時進行資料脫敏。
- 支援自定義脫敏策略,透過定義策略類和工廠類來實現不同的脫敏邏輯。
- 適用於Web應用中,特別是在物件轉換為JSON響應體時對敏感資料進行脫敏。
綜合來看,Hutool庫因其簡單易用和廣泛的脫敏資料型別支援,可能是最常用的脫敏方式。它提供了一行程式碼就能完成脫敏的便捷方法,適用於多種常見的敏感資訊脫敏場景。而MyBatis-Flex和Jackson則更多地用於特定的ORM和JSON序列化場景。因此,如果要選擇最常用的脫敏方式,Hutool庫可能是首選。
基於SpringBoot
一.Hutool庫
- 配置Maven依賴
<!-- Hutool工具類庫 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.16</version> <!-- 請使用最新的版本號 -->
</dependency>
- 建立一個測試類
package com.curry.desensitization;
import cn.hutool.core.util.DesensitizedUtil;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @Author: 藍影
* @Date: 2024/11/5 19:00
* @Description:hutool脫敏工具測試類
*/
@SpringBootTest //啟動測試類
public class HuToolDesensitizationTest {
/**
* 測試手機號脫敏
*/
@Test
public void testPhoneDesensitization() {
String phone="13723231234";
System.out.println(DesensitizedUtil.mobilePhone(phone));
//輸出:137****1234
}
/**
* 測試銀行卡號脫敏
*/
@Test
public void testBankCardDesensitization() {
String bankCard="6217000130008255666";
System.out.println(DesensitizedUtil.bankCard(bankCard));
//輸出:6217 **** **** *** 5666
}
/**
* 測試身份證號脫敏
*/
@Test
public void testIdCardNumDesensitization() {
String idCardNum="411021199901102321";
//只顯示前4位和後2位
System.out.println(DesensitizedUtil.idCardNum(idCardNum,4,2));
//輸出:4110************21
}
/**
* 測試郵箱脫敏
*/
@Test
public void testPasswordDesensitization() {
String password="www.jd.com_35711";
System.out.println(DesensitizedUtil.password(password));
//輸出:****************
}
}
執行結果為:
二.配合JackSon透過註解方式實現脫敏
專案是基於 Spring Boot 的 web 專案,則可以利用 Spring Boot 自帶的 jackson 自定義序列化實現。它的實現原理其實就是在 json 進行序列化渲染給前端時,進行脫敏
第一步:脫敏策略的列舉(建立一個util包,在util包下建立DesensitizationTypeEnum列舉類)
package com.curry.util;
/**
* @Author: 藍影
* @Date: 2024/11/5 19:06
* @Description:脫敏策略列舉
*/
public enum DesensitizationTypeEnum {
//自定義
MY_RULE,
//使用者id
USER_ID,
//中文名
CHINESE_NAME,
//身份證號
ID_CARD,
//座機號
FIXED_PHONE,
//手機號
MOBILE_PHONE,
//地址
ADDRESS,
//電子郵件
EMAIL,
//密碼
PASSWORD,
//中國大陸車牌,包含普通車輛、新能源車輛
CAR_LICENSE,
//銀行卡
BANK_CARD
}
第二步:定義一個用於脫敏的 Desensitization 註解
@Retention (RetentionPolicy.RUNTIME)
:執行時生效。
@Target (ElementType.FIELD)
:可用在欄位上。
@JacksonAnnotationsInside
:此註解可以點進去看一下是一個元註解,主要是使用者打包其他註解一起使用。
@JsonSerialize
:上面說到過,該註解的作用就是可自定義序列化,可以用在註解上,方法上,欄位上,類上,執行時生效等等,根據提供的序列化類裡面的重寫方法實現自定義序列化。
package com.curry.desensitization;
import com.curry.util.DesensitizationTypeEnum;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Author: 藍影
* @Date: 2024/11/5 19:08
* @Description:desensitization註解
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = DesensitizationSerialize.class)
public @interface Desensitization {
/**
* 脫敏資料型別,在MY_RULE的時候,startInclude和endExclude生效
*/
DesensitizationTypeEnum type() default DesensitizationTypeEnum.MY_RULE;
/**
* 脫敏開始位置(包含)
*/
int startInclude() default 0;
/**
* 脫敏結束位置(不包含)
*/
int endExclude() default 0;
}
注:只有使用了自定義的脫敏列舉 MY_RULE
的時候,開始位置和結束位置才生效
第三步:建立自定的序列化類
這一步是我們實現資料脫敏的關鍵。自定義序列化類繼承 JsonSerializer
,實現 ContextualSerializer
介面,並重寫兩個方法
新建DesensitizationSerialize類
package com.curry.desensitization;
/**
* @Author: 藍影
* @Date: 2024/11/5 19:10
* @Description:
*/
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.DesensitizedUtil;
import com.curry.util.DesensitizationTypeEnum;
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 lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import java.io.IOException;
import java.util.Objects;
/**
* @author
* @description: 自定義序列化類
*/
@AllArgsConstructor
@NoArgsConstructor
public class DesensitizationSerialize extends JsonSerializer<String> implements ContextualSerializer {
private DesensitizationTypeEnum type;
private Integer startInclude;
private Integer endExclude;
@Override
public void serialize(String str, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws
IOException {
switch (type) {
// 自定義型別脫敏
case MY_RULE:
jsonGenerator.writeString(CharSequenceUtil.hide(str, startInclude, endExclude));
break;
// userId脫敏
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), 1, 2));
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:
}
}
@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(), desensitization.startInclude(),
desensitization.endExclude());
}
}
return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
}
return serializerProvider.findNullValueSerializer(null);
}
}
首先定義一個要測試的 pojo,對應的欄位加入要脫敏的策略
package com.curry.Entity;
import com.curry.desensitization.Desensitization;
import com.curry.util.DesensitizationTypeEnum;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @Author: 藍影
* @Date: 2024/11/5 19:16
* @Description:測試pojo類
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class TestPojo {
private String userName;
@Desensitization(type = DesensitizationTypeEnum.MOBILE_PHONE)
private String phone;
@Desensitization(type = DesensitizationTypeEnum.PASSWORD)
private String password;
@Desensitization(type = DesensitizationTypeEnum.MY_RULE, startInclude = 0, endExclude = 2)
private String address;
}
寫一個測試的controller
package com.curry.controller;
import com.curry.Entity.TestPojo;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author: 藍影
* @Date: 2024/11/5 19:15
* @Description:controller測試類
*/
@RestController
public class TestController {
@PostMapping("/test")
public TestPojo testDesensitization(){
TestPojo testPojo = new TestPojo();
testPojo.setUserName("我是使用者名稱");
testPojo.setAddress("地球中國-北京市通州區京東總部2號樓");
testPojo.setPhone("13782946666");
testPojo.setPassword("sunyangwei123123123.");
System.out.println(testPojo);
return testPojo;
}
}
在postman測試結果為