SpringBoot數(shù)據(jù)脫敏的實(shí)現(xiàn)示例
什么是數(shù)據(jù)脫敏
數(shù)據(jù)脫敏,也稱為數(shù)據(jù)的去隱私化或數(shù)據(jù)變形,是一種技術(shù)手段,用于對(duì)某些敏感信息通過特定的脫敏規(guī)則進(jìn)行數(shù)據(jù)的變形,從而實(shí)現(xiàn)敏感隱私數(shù)據(jù)的可靠保護(hù)。這樣可以在開發(fā)、測(cè)試和其他非生產(chǎn)環(huán)境以及外包環(huán)境中安全地使用脫敏后的真實(shí)數(shù)據(jù)集。
數(shù)據(jù)脫敏的主要應(yīng)用場(chǎng)景包括涉及客戶安全數(shù)據(jù)或商業(yè)性敏感數(shù)據(jù)的情況,例如身份證號(hào)、手機(jī)號(hào)、卡號(hào)、客戶號(hào)等個(gè)人信息都需要進(jìn)行數(shù)據(jù)脫敏。數(shù)據(jù)脫敏的主要功能是通過使用數(shù)據(jù)脫敏產(chǎn)品,有效防止企業(yè)內(nèi)部對(duì)隱私數(shù)據(jù)的濫用,防止隱私數(shù)據(jù)在未經(jīng)脫敏的情況下從企業(yè)流出,滿足企業(yè)既要保護(hù)隱私數(shù)據(jù),同時(shí)又保持監(jiān)管合規(guī)的需求。
今天我們就用自定義注解的方式在我們的項(xiàng)目中實(shí)現(xiàn)數(shù)據(jù)脫敏。
@JsonSerialize
@JsonSerialize 是 Jackson 庫(kù)中的一個(gè)注解,用于在將 Java 對(duì)象序列化為 JSON 格式時(shí)指定如何進(jìn)行自定義的序列化處理。Jackson 是一個(gè)流行的 Java 庫(kù),用于處理 JSON 數(shù)據(jù)的序列化和反序列化。
@JsonSerialize 注解可以應(yīng)用于字段、方法或類級(jí)別,允許我們自定義序列化過程。例如,我們可以通過 @JsonSerialize 注解將日期格式化為特定的字符串,或?qū)⒚杜e類型序列化為其名稱而不是值。
在使用 @JsonSerialize 注解時(shí),我們可以使用 using 屬性來指定一個(gè)自定義的序列化器(Serializer)類,這個(gè)類需要繼承自 JsonSerializer,其中 T 是要序列化的對(duì)象的類型。通過這個(gè)自定義的序列化器,我們可以完全控制如何將 Java 對(duì)象轉(zhuǎn)換為 JSON 數(shù)據(jù)。
此外,@JsonSerialize 注解還有一些其他的屬性,如 include,用于指定序列化的范圍和作用規(guī)則(例如,只序列化非空的屬性)。
舉個(gè)簡(jiǎn)單的例子,大家感受下:
@Data
public class CustomDateClass {
@JsonSerialize(using = CustomDateSerializer.class)
private Date myDate;
//自定義的日期序列化器
public static class CustomDateSerializer extends ToStringSerializer<Date> {
private static final long serialVersionUID = 1L;
public CustomDateSerializer() {
//傳遞null以使用默認(rèn)日期格式
super(null);
}
//重寫 serialize 方法來定制日期的序列化過程,將其格式化為 "yyyy-MM-dd" 的字符串。
@Override
public void serialize(Date value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
String formattedDate = new SimpleDateFormat("yyyy-MM-dd").format(value);
jgen.writeString(formattedDate);
}
}
}
接下來我們就使用自定義注解的方式,利用@JsonSerialize注解的特性來實(shí)現(xiàn)今天的數(shù)據(jù)脫敏功能。
自定義Jackson注解
需要自定義一個(gè)脫敏注解,一旦有屬性被標(biāo)注,則進(jìn)行對(duì)應(yīng)的脫敏
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside
@JsonSerialize(using = SensitiveJsonSerializer.class)
public @interface Sensitive {
//脫敏策略
SensitiveStrategy strategy();
}
定制脫敏策略
針對(duì)項(xiàng)目需求,定制不同字段的脫敏規(guī)則,比如手機(jī)號(hào)中間幾位用 * 替代:
/**
* 脫敏策略,枚舉類,針對(duì)不同的數(shù)據(jù)定制特定的策略
*/
public enum SensitiveStrategy
{
/**
* 姓名,第2位星號(hào)替換
*/
USERNAME(s -> s.replaceAll("(\\S)\\S(\\S*)", "$1*$2")),
/**
* 密碼,全部字符都用*代替
*/
PASSWORD(DesensitizedUtil::password),
/**
* 身份證,中間10位星號(hào)替換
*/
ID_CARD(s -> s.replaceAll("(\\d{4})\\d{10}(\\d{4})", "$1** **** ****$2")),
/**
* 手機(jī)號(hào),中間4位星號(hào)替換
*/
PHONE(s -> s.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")),
/**
* 電子郵箱,僅顯示第一個(gè)字母和@后面的地址顯示,其他星號(hào)替換
*/
EMAIL(s -> s.replaceAll("(^.)[^@]*(@.*$)", "$1****$2")),
/**
* 銀行卡號(hào),保留最后4位,其他星號(hào)替換
*/
BANK_CARD(s -> s.replaceAll("\\d{15}(\\d{3})", "**** **** **** **** $1")),
/**
* 車牌號(hào)碼,包含普通車輛、新能源車輛
*/
CAR_LICENSE(DesensitizedUtil::carLicense);
private final Function<String, String> desensitizer;
SensitiveStrategy(Function<String, String> desensitizer)
{
this.desensitizer = desensitizer;
}
public Function<String, String> desensitizer()
{
return desensitizer;
}
}
定制JSON序列化實(shí)現(xiàn)
對(duì)標(biāo)注注解@Sensitive的字段進(jìn)行脫敏
/**
* 序列化注解自定義實(shí)現(xiàn)
* JsonSerializer<String>:指定String 類型,serialize()方法用于將修改后的數(shù)據(jù)載入
*/
public class SensitiveJsonSerializer extends JsonSerializer<String> implements ContextualSerializer {
private SensitiveStrategy strategy;
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeString(strategy.desensitizer().apply(value));
}
/**
* 獲取屬性上的注解屬性
*/
@Override
public 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);
}
}
脫敏工具類
/**
* 脫敏工具類
*/
public class DesensitizedUtil
{
/**
* 密碼的全部字符都用*代替,比如:******
*
* @param password 密碼
* @return 脫敏后的密碼
*/
public static String password(String password)
{
if (StringUtils.isBlank(password))
{
return StringUtils.EMPTY;
}
return StringUtils.repeat('*', password.length());
}
/**
* 車牌中間用*代替,如果是錯(cuò)誤的車牌,不處理
*
* @param carLicense 完整的車牌號(hào)
* @return 脫敏后的車牌
*/
public static String carLicense(String carLicense)
{
if (StringUtils.isBlank(carLicense))
{
return StringUtils.EMPTY;
}
// 普通車牌
if (carLicense.length() == 7)
{
carLicense = StringUtils.hide(carLicense, 3, 6);
}
else if (carLicense.length() == 8)
{
// 新能源車牌
carLicense = StringUtils.hide(carLicense, 3, 7);
}
return carLicense;
}
}
定義Person類,對(duì)其數(shù)據(jù)脫敏
使用注解@Sensitive注解進(jìn)行數(shù)據(jù)脫敏
@Data
public class Person {
/**
* 真實(shí)姓名
*/
@Sensitive(strategy = SensitiveStrategy.USERNAME)
private String realName;
/**
* 電話號(hào)碼
*/
@Sensitive(strategy = SensitiveStrategy.PHONE)
private String phoneNumber;
/**
* 身份證號(hào)碼
*/
@Sensitive(strategy = SensitiveStrategy.ID_CARD)
private String idCard;
}
模擬接口測(cè)試
以上4個(gè)步驟完成了數(shù)據(jù)脫敏的Jackson注解,下面寫個(gè)controller進(jìn)行測(cè)試
@RestController
public class TestController {
@GetMapping("/test")
public Person test(){
Person user = new Person();
user.setRealName("阿Q說代碼");
user.setPhoneNumber("13588888888");
user.setIdCard("370213199204174235");
return user;
}
}
返回結(jié)果如下:

總結(jié)
到此這篇關(guān)于SpringBoot數(shù)據(jù)脫敏的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)SpringBoot數(shù)據(jù)脫敏內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot中實(shí)現(xiàn)數(shù)據(jù)脫敏的六種常用方案
- 使用SpringBoot整合Sharding Sphere實(shí)現(xiàn)數(shù)據(jù)脫敏的示例
- SpringBoot中實(shí)現(xiàn)數(shù)據(jù)脫敏處理的方法詳解
- SpringBoot中的數(shù)據(jù)脫敏處理詳解
- SpringBoot敏感數(shù)據(jù)脫敏的處理方式
- 淺析如何在SpringBoot中實(shí)現(xiàn)數(shù)據(jù)脫敏
- SpringBoot動(dòng)態(tài)實(shí)現(xiàn)數(shù)據(jù)脫敏的實(shí)戰(zhàn)指南
相關(guān)文章
全網(wǎng)最深分析SpringBoot MVC自動(dòng)配置失效的原因
這篇文章主要介紹了全網(wǎng)最深分析SpringBoot MVC自動(dòng)配置失效的原因,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
Java數(shù)組轉(zhuǎn)換為L(zhǎng)ist的四種方式
這篇文章主要介紹了Java開發(fā)技巧數(shù)組轉(zhuǎn)List的四種方式總結(jié),每種方式結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-09-09
升級(jí)springboot3之自動(dòng)配置導(dǎo)入失效問題及解決
這篇文章主要介紹了升級(jí)springboot3之自動(dòng)配置導(dǎo)入失效問題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07
Spring中@Service注解的作用與@Controller和@RestController之間區(qū)別
這篇文章主要介紹了Spring中@Service注解的作用與@Controller和@RestController之間的區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2023-03-03
Mybatis的TypeHandler加解密數(shù)據(jù)實(shí)現(xiàn)
在我們數(shù)據(jù)庫(kù)中有些時(shí)候會(huì)保存一些用戶的敏感信息,所以就需要對(duì)這些數(shù)據(jù)進(jìn)行加密,那么本文就介紹了Mybatis的TypeHandler加解密數(shù)據(jù)實(shí)現(xiàn),感興趣的可以了解一下2021-06-06
基于MyBatis插件實(shí)現(xiàn)字段加解密的實(shí)現(xiàn)示例
本文主要介紹了基于MyBatis插件實(shí)現(xiàn)字段加解密的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-11-11

