基于Jackson實(shí)現(xiàn)API接口數(shù)據(jù)脫敏的示例詳解
一、背景
用戶的一些敏感數(shù)據(jù),例如手機(jī)號(hào)、郵箱、身份證等信息,在數(shù)據(jù)庫(kù)以明文存儲(chǔ)(加密存儲(chǔ)見《基于Mybatis-Plus攔截器實(shí)現(xiàn)MySQL數(shù)據(jù)加解密》), 但在接口返回?cái)?shù)據(jù)給瀏覽器(或三方客戶端)時(shí),希望對(duì)這些敏感數(shù)據(jù)進(jìn)行脫敏。 同時(shí)在瀏覽器提交數(shù)據(jù)更新到后端接口時(shí),后端接口需要判斷敏感數(shù)據(jù)是否已脫敏,如果已脫敏則需要直接丟棄。

二、Jackson介紹
Jackson是SpringBoot默認(rèn)的Json序列化和反序列化庫(kù),點(diǎn)擊這里查看Jackson注解官方文檔.
本文通過使用Jackson的@JsonSerialize注解實(shí)現(xiàn)序列化時(shí)脫敏操作,通過使用Jackson的@JsonDeserialize注解實(shí)現(xiàn)反序列化時(shí)脫敏數(shù)據(jù)檢測(cè)并丟棄操作。
三、使用方法
該脫敏攔截器功能在wutong-base-api包(公司內(nèi)部包)已經(jīng)實(shí)現(xiàn),如果您的項(xiàng)目已經(jīng)依賴了base-api,就可以直接使用。
另外,在碼云上有Demo案例,見: spring-jackson
基于wutong-base-api包的使用步驟如下。
1、添加wutong-base-api依賴
<dependency>
<groupId>com.talkweb</groupId>
<artifactId>wutong-base-api</artifactId>
<version>請(qǐng)使用最新版本</version>
</dependency>2、在yaml配置開關(guān),啟用加解密
spring:
jackson:
sensitive:
# 序列化時(shí)是否對(duì)手機(jī)號(hào)進(jìn)行脫敏,反序列化時(shí)是否過濾脫敏數(shù)據(jù)
mobile: true
# 序列化時(shí)是否對(duì)郵箱進(jìn)行脫敏,反序列化時(shí)是否過濾脫敏數(shù)據(jù)
email: true
# 序列化時(shí)是否對(duì)身份證號(hào)進(jìn)行脫敏,反序列化時(shí)是否過濾脫敏數(shù)據(jù)
identity: true3、定義VO類,使用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),過濾已脫敏的數(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)ⅲ?
無
出參:
{
"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)脫敏開關(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)文章
簡(jiǎn)單聊聊SpringBoot性能優(yōu)化的12個(gè)小技巧
這篇文章主要想來和大家簡(jiǎn)單聊聊SpringBoot性能優(yōu)化的12個(gè)小技巧,文中的示例代碼簡(jiǎn)潔易懂,具有一定的借鑒價(jià)值,有需要的小伙伴可以了解一下2025-05-05
springboot出現(xiàn)DataBufferLimitException: Exceeded lim
在Shenyu網(wǎng)關(guān)中,上傳大文件時(shí)遇到`DataBufferLimitException`異常,問題在于Spring Boot 2版本中`max-in-memory-size`配置無效,通過創(chuàng)建同名類并修改`maxInMemorySize`值來解決問題,此方法利用Spring同名Bean覆蓋機(jī)制,確保自定義類優(yōu)先被加載2026-04-04
Java兩整數(shù)相除向上取整的方式詳解(Math.ceil())
在調(diào)外部接口獲取列表數(shù)據(jù)時(shí),需要判斷是否已經(jīng)取完了所有的值,因此需要用到向上取整,下面這篇文章主要給大家介紹了關(guān)于Java兩整數(shù)相除向上取整的相關(guān)資料,需要的朋友可以參考下2022-06-06
MyBatis是如何實(shí)現(xiàn)日志模塊的詳解
這篇文章主要給大家介紹了關(guān)于MyBatis是如何實(shí)現(xiàn)日志模塊的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者使用MyBatis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10
淺談js文件引用方式及其同步執(zhí)行與異步執(zhí)行
下面小編就為大家?guī)硪黄獪\談js文件引用方式及其同步執(zhí)行與異步執(zhí)行。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-10-10
Springmvc RequestMapping請(qǐng)求實(shí)現(xiàn)方法解析
這篇文章主要介紹了Springmvc RequestMapping請(qǐng)求實(shí)現(xiàn)方法解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09

