SpringBoot3使用?自定義注解+Jackson實(shí)現(xiàn)接口數(shù)據(jù)脫敏的步驟
寫(xiě)在前面
本文介紹了springboot開(kāi)發(fā)后端服務(wù)中,接口數(shù)據(jù)脫敏優(yōu)雅的設(shè)計(jì)與實(shí)現(xiàn),堅(jiān)持看完相信對(duì)你有幫助。
內(nèi)容簡(jiǎn)介
本文介紹了一種以?xún)?yōu)雅的方式實(shí)現(xiàn)對(duì)接口返回的敏感數(shù)據(jù),如手機(jī)號(hào)、郵箱、身份證等信息的脫敏處理。這種方法也是企業(yè)常用方法。話(huà)不多說(shuō)我們一起來(lái)看一下吧。
效果展示:
實(shí)現(xiàn)思路
- 自定義一個(gè)脫敏注解用于標(biāo)記需要脫敏的字段,并且在注解中指定脫敏策略屬性。
- 自定義脫敏策略枚舉類(lèi),用于維護(hù)手機(jī)號(hào)、郵箱、身份證等信息的脫敏處理方式。
- 自定義脫敏 JSON 序列化器,在該序列化器中找到帶有該注解的字段,根據(jù)注解中指定的脫敏策略,在序列化過(guò)程中將數(shù)據(jù)進(jìn)行脫敏處理并輸出到 JSON 中。
實(shí)現(xiàn)步驟
1.自定義脫敏注解
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.mijiu.commom.custom.serializable.DesensitizationJsonSerializable; import com.mijiu.commom.enumerate.DesensitizationStrategyEnum; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @author mijiupro */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) @JacksonAnnotationsInside @JsonSerialize(using = DesensitizationJsonSerializable.class) public @interface Desensitization { DesensitizationStrategyEnum desensitizationStrategy();//這是自定義的脫敏策略枚舉類(lèi)型,用于指定脫敏策略,獲取對(duì)應(yīng)脫敏處理方法 }
2.編寫(xiě)脫敏策略枚舉類(lèi)
脫敏的本質(zhì)其實(shí)就是個(gè)字符串的替換,我們?cè)诿撁舨呗悦杜e類(lèi)中通過(guò)定義函數(shù)接口,維護(hù)多種類(lèi)型脫敏策略對(duì)應(yīng)的字符串替換方法。這樣做可以保證可維護(hù)性可擴(kuò)展性。
import lombok.Getter; import java.util.function.Function; /** * 脫敏策略枚舉類(lèi),維護(hù)對(duì)不同類(lèi)型信息的脫敏處理方式 * @author mijiupro */ @Getter public enum DesensitizationStrategyEnum { // 手機(jī)號(hào)脫敏策略,保留前三位和后四位 PHONE(s -> s.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")), // 郵箱脫敏策略,保留郵箱用戶(hù)名第一個(gè)字符和@符號(hào)前后部分 EMAIL(s -> s.replaceAll("(\\w)[^@]*(@\\w+\\.\\w+)", "$1****$2")), // 身份證號(hào)脫敏策略,保留前四位和后四位 ID_CARD(s -> s.replaceAll("(\\d{4})\\d{10}(\\w{4})", "$1*****$2")), // 地址脫敏策略,保留省市信息,其余部分脫敏為** ADDRESS(s -> s.replaceAll("([\\u4e00-\\u9fa5]{2})[\\u4e00-\\u9fa5]+", "$1**")), // 銀行卡號(hào)脫敏策略,保留前四位和后三位 BANK_CARD(s -> s.replaceAll("(\\d{4})\\d{8,12}(\\d{3})", "$1************$2")), // 姓名脫敏策略,保留姓氏第一個(gè)字符,其余部分脫敏為** NAME(s -> s.charAt(0) + "**"), // 密碼脫敏策略,統(tǒng)一顯示為****** PASSWORD(s -> "******"); private final Function<String, String> desensitization; DesensitizationStrategyEnum(Function<String, String> desensitization) { this.desensitization = desensitization; } }
3.編寫(xiě)JSON序列化實(shí)現(xiàn)
需要清楚
- 平時(shí)接口返回的數(shù)據(jù)結(jié)構(gòu)直接都是交給默認(rèn)的序列化器把對(duì)象轉(zhuǎn)成json的。
- 實(shí)現(xiàn)脫敏的本質(zhì)就是在這前面添加了一段邏輯,找到帶有脫敏注解的屬性然后拿到注解指定的脫敏策略實(shí)例化這個(gè)脫敏策略枚舉類(lèi),應(yīng)用對(duì)應(yīng)的脫敏方法處理需要脫敏字段,得到脫敏后的值交給json生成器得到最終脫敏后的json
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.ser.ContextualSerializer; import com.mijiu.commom.annotation.Desensitization; import com.mijiu.commom.enumerate.DesensitizationStrategyEnum; import java.io.IOException; import java.util.Objects; /** * 自定義的脫敏JSON序列化器 * @author mijiupro */ public class DesensitizationJsonSerializable extends JsonSerializer<String> implements ContextualSerializer { private DesensitizationStrategyEnum desensitizationStrategy; // 脫敏策略 @Override public void serialize(String s, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { // 將字符串按照設(shè)定的脫敏策略進(jìn)行脫敏處理后序列化到 JSON 中 jsonGenerator.writeString(desensitizationStrategy.getDesensitization().apply(s)); } @Override public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException { // 獲取屬性上的 Desensitization 注解 Desensitization annotation = beanProperty.getAnnotation(Desensitization.class); // 判斷注解不為空且屬性類(lèi)型為 String if (Objects.nonNull(annotation) && Objects.equals(String.class, beanProperty.getType().getRawClass())) { this.desensitizationStrategy = annotation.desensitizationStrategy(); // 設(shè)置脫敏策略 return this; } // 返回默認(rèn)的序列化器 return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty); } }
4.編寫(xiě)測(cè)試類(lèi)
/** * @author mijiupro */ @Data @Builder public class PersonalInfo { @Desensitization(desensitizationStrategy = DesensitizationStrategyEnum.PHONE) private String phone; // 手機(jī)號(hào) @Desensitization(desensitizationStrategy = DesensitizationStrategyEnum.EMAIL) private String email; // 郵箱 @Desensitization(desensitizationStrategy = DesensitizationStrategyEnum.ID_CARD) private String idCard; // 身份證號(hào) @Desensitization(desensitizationStrategy = DesensitizationStrategyEnum.ADDRESS) private String address; // 地址 @Desensitization(desensitizationStrategy = DesensitizationStrategyEnum.BANK_CARD) private String bankCard; // 銀行卡號(hào) @Desensitization(desensitizationStrategy = DesensitizationStrategyEnum.NAME) private String name; // 姓名 @Desensitization(desensitizationStrategy = DesensitizationStrategyEnum.PASSWORD) private String password; // 密碼 }
5.編寫(xiě)測(cè)試接口
/** * @author mijiupro */ @RestController @RequestMapping("/test/desensitization") @Tag(name = "脫敏測(cè)試接口", description = "脫敏測(cè)試接口") public class DesensitizationTestController { @GetMapping("/get-info") @Operation(summary = "獲取脫敏信息") public PersonalInfo getInt() { return PersonalInfo.builder() .name("言冰云") .phone("13812345678") .email("mijiu@qq.com") .idCard("110101199003073321") .address("四川省成都市郫都區(qū)百草路一號(hào)") .password("1234567890") .bankCard("62220210001234567890") .build(); } }
6.接口測(cè)試
這里通過(guò)swagger3進(jìn)行接口測(cè)試:
springboot3整合knife4j詳細(xì)圖文教程(swagger增強(qiáng))_java_腳本之家 (jb51.net)
測(cè)試結(jié)果:
寫(xiě)在最后
springboot3實(shí)現(xiàn)優(yōu)雅的數(shù)據(jù)脫敏到這里就結(jié)束了,本文共列舉了實(shí)現(xiàn)了七種常見(jiàn)的類(lèi)型的數(shù)據(jù)脫敏。
以上就是SpringBoot3使用?自定義注解+Jackson實(shí)現(xiàn)接口數(shù)據(jù)脫敏的步驟的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot3接口數(shù)據(jù)脫敏的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
從源碼角度看spring mvc的請(qǐng)求處理過(guò)程
這篇文章主要介紹了從源碼角度看spring mvc的請(qǐng)求處理過(guò)程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,,需要的朋友可以參考下2019-06-06淺談JAVA字符串匹配算法indexOf函數(shù)的實(shí)現(xiàn)方法
這篇文章主要介紹了淺談字符串匹配算法indexOf函數(shù)的實(shí)現(xiàn)方法,indexOf函數(shù)我們可以查找一個(gè)字符串(模式串)是否在另一個(gè)字符串(主串)出現(xiàn)過(guò)。對(duì)此感興趣的可以來(lái)了解一下2020-07-07簡(jiǎn)單了解mybatis攔截器實(shí)現(xiàn)原理及實(shí)例
這篇文章主要介紹了簡(jiǎn)單了解mybatis攔截器實(shí)現(xiàn)原理及實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-01-01SpringBoot自定義FailureAnalyzer詳解
這篇文章主要介紹了SpringBoot自定義FailureAnalyzer詳解,FailureAnalyzer是一種在啟動(dòng)時(shí)攔截?exception?并將其轉(zhuǎn)換為?human-readable?消息的好方法,包含在故障分析中,需要的朋友可以參考下2023-11-11SpringBoot處理跨域請(qǐng)求(CORS)的五種方式
跨域資源共享(CORS)是現(xiàn)代Web開(kāi)發(fā)中常見(jiàn)的問(wèn)題,Spring?Boot提供了多種方式來(lái)處理CORS請(qǐng)求,下面我將詳細(xì)介紹各種實(shí)現(xiàn)方式及其適用場(chǎng)景,需要的朋友可以參考下2025-04-04JeecgBoot框架升級(jí)至Spring?Boot3的實(shí)戰(zhàn)步驟
本文主要介紹了JeecgBoot框架升級(jí)至Spring?Boot3的實(shí)戰(zhàn)步驟,從?2.7.10升級(jí)到3.1.5有以下幾個(gè)點(diǎn)需要注意,下面就來(lái)詳細(xì)的介紹一下,感興趣的可以了解一下2024-04-04Java 實(shí)現(xiàn)限流器處理Rest接口請(qǐng)求詳解流程
在工作中是否會(huì)碰到這樣的場(chǎng)景,高并發(fā)的請(qǐng)求但是無(wú)法全部執(zhí)行,需要一定的限流。如果你是使用的微服務(wù)框架,比如SpringCloud,可以使用Gateway增加限流策略來(lái)解決。本篇文章是在沒(méi)有框架的情況實(shí)現(xiàn)限流器2021-11-11Java實(shí)用工具庫(kù)commons-lang3的使用
Apache?Commons?Lang?3是一個(gè)流行的Java實(shí)用工具庫(kù),提供了對(duì)java.lang包的擴(kuò)展,包括字符串操作、正則表達(dá)式處理、數(shù)字操作、日期和時(shí)間操作、隨機(jī)字符串生成和對(duì)象操作等功能2025-03-03