Java日志脱敏工具类(支持自定义逻辑)

背景

在开发过程中,很容易将用户敏感信息,例如手机号码、身份证等,打印在日志平台。为了保护用户数据,又不影响日志的打印,需要将日志中的敏感信息进行脱敏。

效果

强烈建议 pull项目,执行一下项目中SensitiveUtils#main方法。

特性

  1. 支持多层级【JSON】/【对象】字段脱敏
  2. 支持一次多字段脱敏
  3. 支持自定义脱敏逻辑
  4. 支持一次脱敏多种数据类型,例如:一个字符串同时脱敏手机号、身份证号
  5. 连续数组层级脱敏
  6. 减少侵入业务代码(例如使用注解进行脱敏)

使用

1. 输入为字符串/对象及单JSON路径

   // 传入对象
   User user = new User();
   user.setName("handsometaoa");
   user.setPhone("13455556666");
   List<SensitivePath> sensitivePaths = Collections.singletonList(SensitivePath.withBuiltInRule("phone", DesensitizedType.MOBILE_PHONE));
   String result1 = SensitiveUtils.des(user, new HashSet<>(sensitivePaths));
   System.out.println(result1); // {"phone":"134****6666","name":"handsometaoa"}
   
   // 传入JSON字符串
   String param2 = "{\"name\":\"handsometaoa\",\"phone\":\"13455556666\"}";
   List<SensitivePath> sensitivePaths2 = Collections.singletonList(SensitivePath.withBuiltInRule("phone", DesensitizedType.MOBILE_PHONE));
   String result2 = SensitiveUtils.des(param2, new HashSet<>(sensitivePaths2));
   System.out.println(result2); // {"phone":"134****6666","name":"handsometaoa"}

2. 输入为字符串/对象及多JSON路径

   [
       {
           "name": "handsometaoa",
           "phone": "13444445555",
           "parent": [
               {
                   "name": "handsometaoa",
                   "phone": "13444445555"
               }
           ]
       },
       {
           "name": "handsometaoa",
           "phone": "13444445555",
           "parent": [
               {
                   "name": "handsometaoa",
                   "phone": "13444445555",
                   "parent": [
                       {
                           "name": "handsometaoa",
                           "phone": "13444445555"
                       }
                   ]
               }
           ]
       }
   ]

上图中,如果要脱敏全部手机号,路径则为 :phone , parent#phone , parent#parent#phone

   String param3 = "[{\"name\":\"handsometaoa\",\"phone\":\"13444445555\",\"parent\":[{\"name\":\"handsometaoa\",\"phone\":\"13444445555\"}]}" +
           ",{\"name\":\"handsometaoa\",\"phone\":\"13444445555\",\"parent\":[{\"name\":\"handsometaoa\",\"phone\":\"13444445555\",\"parent\"" +
           ":[{\"name\":\"handsometaoa\",\"phone\":\"13444445555\"}]}]}]";
   Set<SensitivePath> sensitivePaths3 = SensitivePath.withBuiltInRuleSet(Arrays.asList("phone","parent#phone","parent#parent#phone")
           , DesensitizedType.MOBILE_PHONE);
   String result3 = SensitiveUtils.des(param3, sensitivePaths3);
   System.out.println(result3);

结果展示:

   [
       {
           "parent": [
               {
                   "phone": "134****5555",
                   "name": "handsometaoa"
               }
           ],
           "phone": "134****5555",
           "name": "handsometaoa"
       },
       {
           "parent": [
               {
                   "parent": [
                       {
                           "phone": "134****5555",
                           "name": "handsometaoa"
                       }
                   ],
                   "phone": "134****5555",
                   "name": "handsometaoa"
               }
           ],
           "phone": "134****5555",
           "name": "handsometaoa"
       }
   ]

3. 连续数组JSON脱敏

   [
       [
           {
               "parent": [
                   {
                       "phone": "15555555555"
                   },
                   {
                       "phone": "15555555555"
                   }
               ]
           },
           {
               "parent": [
                   [
                       [
                           {
                               "phone": "15555555555"
                           },
                           {
                               "phone": "15555555555"
                           }
                       ]
                   ]
               ]
           }
       ],
       [
           {
               "parent": [
                   {
                       "phone": "15555555555"
                   }
               ]
           }
       ]
   ]

分析可知,上图中,如果要脱敏全部手机号,路径则为 :parent#phone

           String param4 = "[[{\"parent\":[{\"phone\":\"15555555555\"},{\"phone\":\"15555555555\"}]},{\"parent\":[[[{\"phone\":\"15555555555\"}" +
                   ",{\"phone\":\"15555555555\"}]]]}],[{\"parent\":[{\"phone\":\"15555555555\"}]}]]";
           Set<SensitivePath> sensitivePaths4 = SensitivePath.withBuiltInRuleSet(Collections.singletonList("parent#phone")
                   , DesensitizedType.MOBILE_PHONE);
           String result4 = SensitiveUtils.des(param4, sensitivePaths4);
           System.out.println(result4);

结果展示:

   [
       [
           {
               "parent": [
                   {
                       "phone": "155****5555"
                   },
                   {
                       "phone": "155****5555"
                   }
               ]
           },
           {
               "parent": [
                   [
                       [
                           {
                               "phone": "155****5555"
                           },
                           {
                               "phone": "155****5555"
                           }
                       ]
                   ]
               ]
           }
       ],
       [
           {
               "parent": [
                   {
                       "phone": "155****5555"
                   }
               ]
           }
       ]
   ]

4. 同时脱敏手机号与密码

   {
       "name": "handsometaoa",
       "password": "123123123",
       "phone": "13444445555"
   }

分析可知,上图中,如果要脱敏手机号和密码

   String param5 = "{\"name\":\"handsometaoa\",\"password\":\"123123123\",\"phone\":\"13444445555\"}";
   SensitivePath sensitivePaths51 = SensitivePath.withBuiltInRule("password", DesensitizedType.PASSWORD);
   SensitivePath sensitivePaths52 = SensitivePath.withBuiltInRule("phone", DesensitizedType.MOBILE_PHONE);
   HashSet<SensitivePath> sensitivePaths5 = new HashSet<>(Arrays.asList(sensitivePaths51,sensitivePaths52));
   String result5 = SensitiveUtils.des(param5, sensitivePaths5);
   System.out.println(result5);

结果展示:

   {
       "password": "*********",
       "phone": "134****5555",
       "name": "handsometaoa"
   }

5. 支持自定义脱敏逻辑

   {
       "name": "张一二"
   }

如果想要脱敏上面代码中名字,只留姓名,则可以自定义脱敏逻辑

   String param6 = "{\"name\":\"张一二\"}";
   SensitivePath sensitivePath = SensitivePath.withCustomRule("name", value -> {
       if (ToolUtils.isEmpty( value)){
           return "";
       }
       return MaskUtils.replaceWithAsterisk(value, 1, value.length());
   });
   String result6 = SensitiveUtils.des(param6, Collections.singleton(sensitivePath));
   System.out.println(result6);

结果展示:

   {
       "name": "张**"
   }

已知缺陷

  1. 暂不支持对String以外类型脱敏
  2. 暂不支持字符串中【对象JSON字符串】脱敏
    {
        "info": "{\"data\":\"{\\\"phone\\\":\\\"13444444444\\\"}\"}"
    }
    

未来优化方向

  1. 增加更多脱敏类型(如身份证号码) 已支持 2025-12-04
  2. 支持一个对象/JSON字符串多种脱敏类型,例如:一个字符串同时脱敏手机号、身份证号 已支持 2025-12-04
  3. 连续数组脱敏(待定) 已支持 2025-12-04
  4. 支持非String类型字段脱敏(待定)
  5. 字符串中【对象JSON字符串】脱敏(待定)

Github地址

https://github.com/handsometaoa/SensitiveUtils

posted @ 2024-11-30 21:31  帅气的涛啊  阅读(661)  评论(0)    收藏  举报