自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

如何對數(shù)據(jù)進行脫敏處理?

開發(fā) 前端
實際的業(yè)務(wù)開發(fā)過程中,我們經(jīng)常需要對用戶的隱私數(shù)據(jù)進行脫敏處理,所謂脫敏處理其實就是將數(shù)據(jù)進行混淆隱藏,例如下圖,將用戶的手機號、地址等數(shù)據(jù)信息,采用*進行隱藏,以免泄露個人隱私信息。

[[430398]]

一、背景

實際的業(yè)務(wù)開發(fā)過程中,我們經(jīng)常需要對用戶的隱私數(shù)據(jù)進行脫敏處理,所謂脫敏處理其實就是將數(shù)據(jù)進行混淆隱藏,例如下圖,將用戶的手機號、地址等數(shù)據(jù)信息,采用*進行隱藏,以免泄露個人隱私信息。

如果需要脫敏的數(shù)據(jù)范圍很小很小,甚至就是指定的字段,一般的處理方式也很簡單,就是寫一個隱藏方法即可實現(xiàn)數(shù)據(jù)脫敏。

如果是需求很少的情況下,采用這種方式實現(xiàn)沒太大問題,好維護!

但如果是類似上面那種很多位置的數(shù)據(jù),需要分門別類的進行脫敏處理,通過這種簡單粗暴的處理,代碼似乎就顯得不太優(yōu)雅了。

思考一下,我們可不可以在數(shù)據(jù)輸出的階段,進行統(tǒng)一數(shù)據(jù)脫敏處理,這樣就可以省下不少體力活。

說到數(shù)據(jù)輸出,很多同學可能會想到 JSON 序列化。是的沒錯,我們所熟悉的 web 系統(tǒng),就是將數(shù)據(jù)通過 json 序列化之后展示給前端。

那么問題來了,如何在序列化的時候,進行數(shù)據(jù)脫敏處理呢?

廢話不多說,代碼直接擼上!

二、程序?qū)嵺`

2.1、首先添加依賴包

默認的情況下,如果當前項目已經(jīng)添加了spring-web包或者spring-boot-starter-web包,因為這些jar包已經(jīng)集成了jackson相關(guān)包,因此無需重復依賴。

如果當前項目沒有jackson包,可以通過如下方式進行添加相關(guān)依賴包。

  1. <!--jackson依賴--> 
  2. <dependency> 
  3.     <groupId>com.fasterxml.jackson.core</groupId> 
  4.     <artifactId>jackson-core</artifactId> 
  5.     <version>2.9.8</version> 
  6. </dependency> 
  7. <dependency> 
  8.     <groupId>com.fasterxml.jackson.core</groupId> 
  9.     <artifactId>jackson-annotations</artifactId> 
  10.     <version>2.9.8</version> 
  11. </dependency> 
  12. <dependency> 
  13.     <groupId>com.fasterxml.jackson.core</groupId> 
  14.     <artifactId>jackson-databind</artifactId> 
  15.     <version>2.9.8</version> 
  16. </dependency> 

 

2.2、編寫脫敏類型枚舉類,滿足不同場景的處理

  1. public enum SensitiveEnum { 
  2.  
  3.     /** 
  4.      * 中文名 
  5.      */ 
  6.     CHINESE_NAME, 
  7.  
  8.     /** 
  9.      * 身份證號 
  10.      */ 
  11.     ID_CARD, 
  12.  
  13.     /** 
  14.      * 座機號 
  15.      */ 
  16.     FIXED_PHONE, 
  17.  
  18.     /** 
  19.      * 手機號 
  20.      */ 
  21.     MOBILE_PHONE, 
  22.  
  23.     /** 
  24.      * 地址 
  25.      */ 
  26.     ADDRESS, 
  27.  
  28.     /** 
  29.      * 電子郵件 
  30.      */ 
  31.     EMAIL, 
  32.  
  33.     /** 
  34.      * 銀行卡 
  35.      */ 
  36.     BANK_CARD, 
  37.  
  38.     /** 
  39.      * 公司開戶銀行聯(lián)號 
  40.      */ 
  41.     CNAPS_CODE 

2.3、編寫脫敏注解類

  1. import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; 
  2. import com.fasterxml.jackson.databind.annotation.JsonSerialize; 
  3. import java.lang.annotation.Retention; 
  4. import java.lang.annotation.RetentionPolicy; 
  5.  
  6. @Retention(RetentionPolicy.RUNTIME) 
  7. @JacksonAnnotationsInside 
  8. @JsonSerialize(using = SensitiveSerialize.class) 
  9. public @interface SensitiveWrapped { 
  10.  
  11.     /** 
  12.      * 脫敏類型 
  13.      * @return 
  14.      */ 
  15.     SensitiveEnum value(); 

2.4、編寫脫敏序列化類

  1. import com.fasterxml.jackson.core.JsonGenerator; 
  2. import com.fasterxml.jackson.databind.BeanProperty; 
  3. import com.fasterxml.jackson.databind.JsonMappingException; 
  4. import com.fasterxml.jackson.databind.JsonSerializer; 
  5. import com.fasterxml.jackson.databind.SerializerProvider; 
  6. import com.fasterxml.jackson.databind.ser.ContextualSerializer; 
  7. import java.io.IOException; 
  8. import java.util.Objects; 
  9.  
  10. public class SensitiveSerialize extends JsonSerializer<String> implements ContextualSerializer { 
  11.  
  12.     /** 
  13.      * 脫敏類型 
  14.      */ 
  15.     private SensitiveEnum type; 
  16.  
  17.      
  18.     @Override 
  19.     public void serialize(String s, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { 
  20.         switch (this.type) { 
  21.             case CHINESE_NAME: { 
  22.                 jsonGenerator.writeString(SensitiveInfoUtils.chineseName(s)); 
  23.                 break; 
  24.             } 
  25.             case ID_CARD: { 
  26.                 jsonGenerator.writeString(SensitiveInfoUtils.idCardNum(s)); 
  27.                 break; 
  28.             } 
  29.             case FIXED_PHONE: { 
  30.                 jsonGenerator.writeString(SensitiveInfoUtils.fixedPhone(s)); 
  31.                 break; 
  32.             } 
  33.             case MOBILE_PHONE: { 
  34.                 jsonGenerator.writeString(SensitiveInfoUtils.mobilePhone(s)); 
  35.                 break; 
  36.             } 
  37.             case ADDRESS: { 
  38.                 jsonGenerator.writeString(SensitiveInfoUtils.address(s, 4)); 
  39.                 break; 
  40.             } 
  41.             case EMAIL: { 
  42.                 jsonGenerator.writeString(SensitiveInfoUtils.email(s)); 
  43.                 break; 
  44.             } 
  45.             case BANK_CARD: { 
  46.                 jsonGenerator.writeString(SensitiveInfoUtils.bankCard(s)); 
  47.                 break; 
  48.             } 
  49.             case CNAPS_CODE: { 
  50.                 jsonGenerator.writeString(SensitiveInfoUtils.cnapsCode(s)); 
  51.                 break; 
  52.             } 
  53.         } 
  54.     } 
  55.  
  56.     @Override 
  57.     public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException { 
  58.         // 為空直接跳過 
  59.         if (beanProperty != null) { 
  60.             // 非 String 類直接跳過 
  61.             if (Objects.equals(beanProperty.getType().getRawClass(), String.class)) { 
  62.                 SensitiveWrapped sensitiveWrapped = beanProperty.getAnnotation(SensitiveWrapped.class); 
  63.                 if (sensitiveWrapped == null) { 
  64.                     sensitiveWrapped = beanProperty.getContextAnnotation(SensitiveWrapped.class); 
  65.                 } 
  66.                 if (sensitiveWrapped != null) { 
  67.                     // 如果能得到注解,就將注解的 value 傳入 SensitiveSerialize 
  68.                     return new SensitiveSerialize(sensitiveWrapped.value()); 
  69.                 } 
  70.             } 
  71.             return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty); 
  72.         } 
  73.         return serializerProvider.findNullValueSerializer(beanProperty); 
  74.     } 
  75.  
  76.     public SensitiveSerialize() {} 
  77.  
  78.     public SensitiveSerialize(final SensitiveEnum type) { 
  79.         this.type = type; 
  80.     } 

其中createContextual的作用是通過字段已知的上下文信息定制JsonSerializer對象。

2.5、編寫脫敏工具類

  1. import org.apache.commons.lang3.StringUtils; 
  2.  
  3. public class SensitiveInfoUtils { 
  4.  
  5.     /** 
  6.      * [中文姓名] 只顯示第一個漢字,其他隱藏為2個星號<例子:李**> 
  7.      */ 
  8.     public static String chineseName(final String fullName) { 
  9.         if (StringUtils.isBlank(fullName)) { 
  10.             return ""
  11.         } 
  12.         final String name = StringUtils.left(fullName, 1); 
  13.         return StringUtils.rightPad(name, StringUtils.length(fullName), "*"); 
  14.     } 
  15.  
  16.     /** 
  17.      * [中文姓名] 只顯示第一個漢字,其他隱藏為2個星號<例子:李**> 
  18.      */ 
  19.     public static String chineseName(final String familyName, final String givenName) { 
  20.         if (StringUtils.isBlank(familyName) || StringUtils.isBlank(givenName)) { 
  21.             return ""
  22.         } 
  23.         return chineseName(familyName + givenName); 
  24.     } 
  25.  
  26.     /** 
  27.      * [身份證號] 顯示最后四位,其他隱藏。共計18位或者15位。<例子:420**********5762> 
  28.      */ 
  29.     public static String idCardNum(final String id) { 
  30.         if (StringUtils.isBlank(id)) { 
  31.             return ""
  32.         } 
  33.  
  34.         return StringUtils.left(id, 3).concat(StringUtils 
  35.                 .removeStart(StringUtils.leftPad(StringUtils.right(id, 4), StringUtils.length(id), "*"), 
  36.                         "***")); 
  37.     } 
  38.  
  39.     /** 
  40.      * [固定電話] 后四位,其他隱藏<例子:****1234> 
  41.      */ 
  42.     public static String fixedPhone(final String num) { 
  43.         if (StringUtils.isBlank(num)) { 
  44.             return ""
  45.         } 
  46.         return StringUtils.leftPad(StringUtils.right(num, 4), StringUtils.length(num), "*"); 
  47.     } 
  48.  
  49.     /** 
  50.      * [手機號碼] 前三位,后四位,其他隱藏<例子:138******1234> 
  51.      */ 
  52.     public static String mobilePhone(final String num) { 
  53.         if (StringUtils.isBlank(num)) { 
  54.             return ""
  55.         } 
  56.         return StringUtils.left(num, 3).concat(StringUtils 
  57.                 .removeStart(StringUtils.leftPad(StringUtils.right(num, 4), StringUtils.length(num), "*"), 
  58.                         "***")); 
  59.  
  60.     } 
  61.  
  62.     /** 
  63.      * [地址] 只顯示到地區(qū),不顯示詳細地址;我們要對個人信息增強保護<例子:北京市海淀區(qū)****> 
  64.      * 
  65.      * @param sensitiveSize 敏感信息長度 
  66.      */ 
  67.     public static String address(final String address, final int sensitiveSize) { 
  68.         if (StringUtils.isBlank(address)) { 
  69.             return ""
  70.         } 
  71.         final int length = StringUtils.length(address); 
  72.         return StringUtils.rightPad(StringUtils.left(address, length - sensitiveSize), length, "*"); 
  73.     } 
  74.  
  75.     /** 
  76.      * [電子郵箱] 郵箱前綴僅顯示第一個字母,前綴其他隱藏,用星號代替,@及后面的地址顯示<例子:g**@163.com> 
  77.      */ 
  78.     public static String email(final String email) { 
  79.         if (StringUtils.isBlank(email)) { 
  80.             return ""
  81.         } 
  82.         final int index = StringUtils.indexOf(email, "@"); 
  83.         if (index <= 1) { 
  84.             return email; 
  85.         } else { 
  86.             return StringUtils.rightPad(StringUtils.left(email, 1), index"*"
  87.                     .concat(StringUtils.mid(email, index, StringUtils.length(email))); 
  88.         } 
  89.     } 
  90.  
  91.     /** 
  92.      * [銀行卡號] 前六位,后四位,其他用星號隱藏每位1個星號<例子:6222600**********1234> 
  93.      */ 
  94.     public static String bankCard(final String cardNum) { 
  95.         if (StringUtils.isBlank(cardNum)) { 
  96.             return ""
  97.         } 
  98.         return StringUtils.left(cardNum, 6).concat(StringUtils.removeStart( 
  99.                 StringUtils.leftPad(StringUtils.right(cardNum, 4), StringUtils.length(cardNum), "*"), 
  100.                 "******")); 
  101.     } 
  102.  
  103.     /** 
  104.      * [公司開戶銀行聯(lián)號] 公司開戶銀行聯(lián)行號,顯示前兩位,其他用星號隱藏,每位1個星號<例子:12********> 
  105.      */ 
  106.     public static String cnapsCode(final String code) { 
  107.         if (StringUtils.isBlank(code)) { 
  108.             return ""
  109.         } 
  110.         return StringUtils.rightPad(StringUtils.left(code, 2), StringUtils.length(code), "*"); 
  111.     } 
  112.  

2.6、編寫測試實體類

最后,我們編寫一個實體類UserEntity,看看轉(zhuǎn)換后的效果如何?

  1. public class UserEntity { 
  2.  
  3.     /** 
  4.      * 用戶ID 
  5.      */ 
  6.     private Long userId; 
  7.  
  8.     /** 
  9.      * 用戶姓名 
  10.      */ 
  11.     private String name
  12.  
  13.     /** 
  14.      * 手機號 
  15.      */ 
  16.     @SensitiveWrapped(SensitiveEnum.MOBILE_PHONE) 
  17.     private String mobile; 
  18.  
  19.     /** 
  20.      * 身份證號碼 
  21.      */ 
  22.     @SensitiveWrapped(SensitiveEnum.ID_CARD) 
  23.     private String idCard; 
  24.  
  25.     /** 
  26.      * 年齡 
  27.      */ 
  28.     private String sex; 
  29.  
  30.     /** 
  31.      * 性別 
  32.      */ 
  33.     private int age; 
  34.  
  35.     //省略get、set... 

測試程序如下:

  1. public class SensitiveDemo { 
  2.  
  3.     public static void main(String[] args) throws JsonProcessingException { 
  4.         UserEntity userEntity = new UserEntity(); 
  5.         userEntity.setUserId(1l); 
  6.         userEntity.setName("張三"); 
  7.         userEntity.setMobile("18000000001"); 
  8.         userEntity.setIdCard("420117200001011000008888"); 
  9.         userEntity.setAge(20); 
  10.         userEntity.setSex("男"); 
  11.  
  12.         //通過jackson方式,將對象序列化成json字符串 
  13.         ObjectMapper objectMapper = new ObjectMapper(); 
  14.         System.out.println(objectMapper.writeValueAsString(userEntity)); 
  15.     } 

結(jié)果如下:

  1. {"userId":1,"name":"張三","mobile":"180****0001","idCard":"420*****************8888","sex":"男","age":20} 

很清晰的看到,轉(zhuǎn)換結(jié)果成功!

如果你當前的項目是基于SpringMVC框架進行開發(fā)的,那么在對象返回的時候,框架會自動幫你采用jackson框架進行序列化。

  1. @RequestMapping("/hello"
  2. public UserEntity hello() { 
  3.     UserEntity userEntity = new UserEntity(); 
  4.     userEntity.setUserId(1l); 
  5.     userEntity.setName("張三"); 
  6.     userEntity.setMobile("18000000001"); 
  7.     userEntity.setIdCard("420117200001011000008888"); 
  8.     userEntity.setAge(20); 
  9.     userEntity.setSex("男"); 
  10.     return userEntity; 

請求網(wǎng)頁http://127.0.0.1:8080/hello,結(jié)果如下:

三、小結(jié)

在實際的業(yè)務(wù)場景開發(fā)中,采用注解方式進行全局數(shù)據(jù)脫敏處理,可以有效的解決敏感數(shù)據(jù)隱私泄露的問題。

本文主要從實操層面對數(shù)據(jù)脫敏處理做了簡單的介紹,可能有些網(wǎng)友還有更好的解決方案,歡迎下方留言,后面如果遇到了好的解決辦法,也會分享給大家,愿對大家有所幫助!

四、參考

1、CSDN - 注解實現(xiàn)json序列化的時候自動進行數(shù)據(jù)脫敏

2、yanbin.blog - 自定義 Jackson 注解與禁用某一特定的注解

 

3、簡書 - 數(shù)據(jù)脫敏處理

 

責任編輯:武曉燕 來源: Java極客技術(shù)
相關(guān)推薦

2021-08-09 15:00:36

SQL數(shù)據(jù)庫

2018-04-25 13:32:31

數(shù)據(jù)保護GDPRCommvault

2009-05-13 09:39:00

數(shù)據(jù)中心網(wǎng)絡(luò)設(shè)備管理

2023-10-07 08:34:27

項目API接口

2009-09-28 09:47:55

Hibernate數(shù)據(jù)

2022-08-02 09:32:47

pandas移動計算

2024-04-07 08:50:00

GenAIAI人工智能

2023-10-10 09:13:15

Python數(shù)據(jù)的操作轉(zhuǎn)換

2018-07-04 06:49:32

數(shù)據(jù)中心遷移服務(wù)器

2023-07-27 08:16:51

數(shù)據(jù)訪問層項目

2010-11-12 14:16:21

SQL游標

2024-02-05 13:39:00

隱私數(shù)據(jù)脫敏

2018-04-16 12:14:34

數(shù)據(jù)科學機器學習神經(jīng)網(wǎng)絡(luò)

2009-09-01 09:45:49

Visual C#對數(shù)

2018-03-08 16:53:21

數(shù)據(jù)中心數(shù)據(jù)海嘯

2014-04-03 13:11:07

數(shù)據(jù)中心雅虎

2009-07-29 17:27:23

數(shù)據(jù)中心CMDBIT

2010-07-22 17:25:23

2020-07-08 15:10:11

Python數(shù)據(jù)分析代碼

2024-01-22 08:46:37

MyBatis數(shù)據(jù)脫敏Spring
點贊
收藏

51CTO技術(shù)棧公眾號