基于Jackson實(shí)現(xiàn)API接口數(shù)據(jù)脫敏的示例詳解
一、背景
用戶(hù)的一些敏感數(shù)據(jù),例如手機(jī)號(hào)、郵箱、身份證等信息,在數(shù)據(jù)庫(kù)以明文存儲(chǔ)(加密存儲(chǔ)見(jiàn)《基于Mybatis-Plus攔截器實(shí)現(xiàn)MySQL數(shù)據(jù)加解密》), 但在接口返回?cái)?shù)據(jù)給瀏覽器(或三方客戶(hù)端)時(shí),希望對(duì)這些敏感數(shù)據(jù)進(jìn)行脫敏。 同時(shí)在瀏覽器提交數(shù)據(jù)更新到后端接口時(shí),后端接口需要判斷敏感數(shù)據(jù)是否已脫敏,如果已脫敏則需要直接丟棄。
二、Jackson介紹
Jackson是SpringBoot默認(rèn)的Json序列化和反序列化庫(kù),點(diǎn)擊這里查看Jackson注解官方文檔.
本文通過(guò)使用Jackson的@JsonSerialize注解實(shí)現(xiàn)序列化時(shí)脫敏操作,通過(guò)使用Jackson的@JsonDeserialize注解實(shí)現(xiàn)反序列化時(shí)脫敏數(shù)據(jù)檢測(cè)并丟棄操作。
三、使用方法
該脫敏攔截器功能在wutong-base-api包(公司內(nèi)部包)已經(jīng)實(shí)現(xiàn),如果您的項(xiàng)目已經(jīng)依賴(lài)了base-api,就可以直接使用。
另外,在碼云上有Demo案例,見(jiàn): spring-jackson
基于wutong-base-api包的使用步驟如下。
1、添加wutong-base-api依賴(lài)
<dependency> <groupId>com.talkweb</groupId> <artifactId>wutong-base-api</artifactId> <version>請(qǐng)使用最新版本</version> </dependency>
2、在yaml配置開(kāi)關(guān),啟用加解密
spring: jackson: sensitive: # 序列化時(shí)是否對(duì)手機(jī)號(hào)進(jìn)行脫敏,反序列化時(shí)是否過(guò)濾脫敏數(shù)據(jù) mobile: true # 序列化時(shí)是否對(duì)郵箱進(jìn)行脫敏,反序列化時(shí)是否過(guò)濾脫敏數(shù)據(jù) email: true # 序列化時(shí)是否對(duì)身份證號(hào)進(jìn)行脫敏,反序列化時(shí)是否過(guò)濾脫敏數(shù)據(jù) identity: true
3、定義VO類(lèi),使用Jackson注解實(shí)現(xiàn)數(shù)據(jù)脫敏
API接口出參(Rsp),敏感數(shù)據(jù)序列化時(shí)脫敏
public class UserRspVO { private Long id; private String name; @JsonSerialize(using = CustomerJackSon.MobileSerialize.class) private String mobile; @JsonSerialize(using = CustomerJackSon.EmailSerialize.class) private String email; @JsonSerialize(using = CustomerJackSon.IdentitySerialize.class) private String identity; }
API接口入?yún)?Req),過(guò)濾已脫敏的數(shù)據(jù),直接丟棄
public class UserReqVO { private Long id; private String name; @JsonDeserialize(using = CustomerJackSon.MobileDeSerialize.class) private String mobile; @JsonDeserialize(using = CustomerJackSon.EmailDeSerialize.class) private String email; @JsonDeserialize(using = CustomerJackSon.IdentityDeSerialize.class) private String identity; }
定義Controller接口
@RestController @RequestMapping("/user") public class UserController { @GetMapping public UserRspVO get() { UserRspVO rsp = new UserRspVO(); rsp.setId(1L); rsp.setName("張三"); rsp.setMobile("18866661234"); rsp.setEmail("zhangsan@qq.com"); rsp.setIdentity("434113199901015566"); return rsp; } @PutMapping public UserRspVO put(@RequestBody UserReqVO req) { System.out.println(req); UserRspVO rsp = new UserRspVO(); BeanUtils.copyProperties(req, rsp); return rsp; } }
接口請(qǐng)求示例:
GET http://localhost:8080/user 入?yún)ⅲ? 無(wú) 出參: { "id": "1", "name": "張三", "mobile": "188****1234", // 配置了mobile=true "email": "zhangsan@qq.com", // 配置了email=false "identity": "434113199901015566" // 未配置identity,默認(rèn)為false }
PUT http://127.0.0.1:8080/user 入?yún)ⅲ? { "id": "12124", "name": "張三", "mobile": "188****1234", "email": "zh****@qq.com", "identity": "434***********5566" } Controller反序列化后接收到的數(shù)據(jù): { "id": "12124", "name": "張三", "mobile": null, // 配置了mobile=true "email": "zh****@qq.com", // 配置了email=false "identity": "434***********5566" // 未配置identity,默認(rèn)為false }
四、實(shí)現(xiàn)原理
1、SpringBoot定義變量實(shí)現(xiàn)脫敏開(kāi)關(guān)
讀取yaml配置
@ConfigurationProperties(prefix = "spring.jackson.sensitive") public class JacksonProperties { private Boolean mobile; private Boolean email; private Boolean identity; }
變量注入到JacksonConfig
@Configuration @EnableConfigurationProperties(JacksonProperties.class) public class JacksonConfig { @Bean public ObjectMapper objectMapper(JacksonProperties props) { ObjectMapper mapper = new ObjectMapper(); ContextAttributes attrs = ContextAttributes.getEmpty() .withSharedAttribute("mobile", props.getMobile()) .withSharedAttribute("email", props.getEmail()) .withSharedAttribute("identity", props.getIdentity()); mapper.setDefaultAttributes(attrs); return mapper; } }
2、實(shí)現(xiàn)序列化、反序列化邏輯
public class CustomerJackSon { /** * 手機(jī)號(hào)脫敏序列化 */ public static class MobileSerialize extends JsonSerializer<String> { @Override public void serialize(String value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { if (null == value || value.length() != 11) { jsonGenerator.writeString(value); return; } Boolean mobile = (Boolean) serializerProvider.getAttribute("mobile"); if (null == mobile || !mobile) { jsonGenerator.writeString(value); return; } jsonGenerator.writeString(value.substring(0, 3) + "****" + value.substring(7)); } } /** * 手機(jī)號(hào)脫敏數(shù)據(jù)檢測(cè)并丟棄 */ public static class MobileDeSerialize extends JsonDeserializer<String> { @Override public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException { String value = p.getText(); if (null == value || value.length() != 11) { return value; } Boolean mobile = (Boolean) ctxt.getAttribute("mobile"); if (null == mobile || !mobile) { return value; } if (value.contains("*")) { return null; } return value; } } /** * 郵箱脫敏序列化 */ public static class EmailSerialize extends JsonSerializer<String> { @Override public void serialize(String value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { if (null == value || value.length() < 5) { jsonGenerator.writeString(value); return; } String[] split = value.split("@"); if (split.length != 2 || split[0].length() < 2 || split[1].length() < 2) { jsonGenerator.writeString(value); return; } Boolean email = (Boolean) serializerProvider.getAttribute("email"); if (null == email || !email) { jsonGenerator.writeString(value); return; } jsonGenerator.writeString(split[0].substring(0, 2) + "****@" + split[1]); } } /** * 郵箱脫敏數(shù)據(jù)檢測(cè)并丟棄 */ public static class EmailDeSerialize extends JsonDeserializer<String> { @Override public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException { String value = p.getText(); if (null == value || value.length() < 5) { return value; } Boolean email = (Boolean) ctxt.getAttribute("email"); if (null == email || !email) { return value; } if (value.contains("*")) { return null; } return value; } } /** * 身份證脫敏序列化 */ public static class IdentitySerialize extends JsonSerializer<String> { @Override public void serialize(String value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { if (null == value || value.length() != 18) { jsonGenerator.writeString(value); return; } Boolean identity = (Boolean) serializerProvider.getAttribute("identity"); if (null == identity || !identity) { jsonGenerator.writeString(value); return; } jsonGenerator.writeString(value.substring(0, 3) + "***********" + value.substring(14)); } } /** * 身份證脫敏數(shù)據(jù)檢測(cè)并丟棄 */ public static class IdentityDeSerialize extends JsonDeserializer<String> { @Override public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException { String value = p.getText(); if (null == value || value.length() != 18) { return value; } Boolean identity = (Boolean) ctxt.getAttribute("identity"); if (null == identity || !identity) { return value; } if (value.contains("*")) { return null; } return value; } } }
以上就是基于Jackson實(shí)現(xiàn)API接口數(shù)據(jù)脫敏的示例詳解的詳細(xì)內(nèi)容,更多關(guān)于Jackson API接口數(shù)據(jù)脫敏的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
【spring-boot】快速構(gòu)建spring-boot微框架的方法
本篇文章主要介紹了【spring-boot】快速構(gòu)建spring-boot微框架的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-12-12SpringBoot集成Curator實(shí)現(xiàn)Zookeeper基本操作的代碼示例
Zookeeper是一個(gè)Apache開(kāi)源的分布式的應(yīng)用,為系統(tǒng)架構(gòu)提供協(xié)調(diào)服務(wù),ZooKeeper的目標(biāo)就是封裝好復(fù)雜易出錯(cuò)的關(guān)鍵服務(wù),將簡(jiǎn)單易用的接口和性能高效、功能穩(wěn)定的系統(tǒng)提供給用戶(hù),本文給大家介紹了SpringBoot集成Curator實(shí)現(xiàn)Zookeeper基本操作,需要的朋友可以參考下2024-05-05SpringBoot3整合WebSocket詳細(xì)指南
SpringBoot 3 整合 WebSocket 提供了一種高效的實(shí)時(shí)通信解決方案,通過(guò)本文的配置和示例,可以快速實(shí)現(xiàn),感興趣的哦朋友跟隨小編一起看看吧2024-12-12在navicat中導(dǎo)入mysql數(shù)據(jù)庫(kù)詳細(xì)步驟(即.sql后綴的數(shù)據(jù)庫(kù))
Navicat是MySQL非常好用的可視化管理工具,功能非常強(qiáng)大,能滿(mǎn)足我們?nèi)粘?shù)據(jù)庫(kù)開(kāi)發(fā)的所有需求,下面這篇文章主要給大家介紹了關(guān)于如何在navicat中導(dǎo)入mysql數(shù)據(jù)庫(kù)(即.sql后綴的數(shù)據(jù)庫(kù))的相關(guān)資料,需要的朋友可以參考下2023-04-04windows下java環(huán)境變量的設(shè)置方法
在“系統(tǒng)變量”中,設(shè)置3項(xiàng)屬性,JAVA_HOME,PATH,CLASSPATH(大小寫(xiě)無(wú)所謂),若已存在則點(diǎn)擊“編輯”,不存在則點(diǎn)擊“新建”2013-09-09Java8如何利用Lambda快速生成map、多層嵌套map
這篇文章主要介紹了Java8如何利用Lambda快速生成map、多層嵌套map問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09