需求
假如D://txt/json.json文件內容如下 , 現期望students列表中的studentName和studentMobile脫敏後返回給前端
{
"teacher": {
"id": "t0001",
"name": "王老師",
"age": 24
},
"students": [
{
"id": "s0001",
"createDate": "2022-08-16 16:37:21",
"updateDate": "2022-08-16 16:37:21",
"studentName": "胡歌",
"studentMobile": "13712345678"
},
{
"id": "s0002",
"createDate": "2022-08-17 16:37:21",
"updateDate": "2022-08-17 16:37:21",
"studentName": "張天愛",
"studentMobile": "13787654321"
}
]
}
依賴
本方法依賴包 ,
fastjson
原理
使用fastjson的JSONPath提取對應路徑下的節點 , 再使用hutool對指定的節點實現脫敏 , 當然hutool在本處並不是絕對必須的 , 脫敏方法可以自己手動修改成不依賴hutool 的 StrUtil.hide(value, startIndex, endIndex); 方法
工具類代碼
package com.rosellete.iescp.cshop.tool;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPath;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 字符串隱藏工具
* fastjson處理脫敏中的指定字段值[原]==>https://www.cnblogs.com/whatlonelytear/p/16594961.html
* @author 金劍波
* @date 2022/08/17
*/
public class HideTool {
public static String IDCARD = "idcard";//身份證
public static String MOBILE = "mobile";//手機
public static String NAME = "name";//姓名
public static void main(String[] args) {
String data = FileUtil.readString("D://txt/json.json", Charset.forName("utf-8"));
//使用方式1,直接指定屬性和脫敏方式,串行轉換,性能較低
Object srcObj1 = JSONObject.parse(data);
srcObj1 = HideTool.doHide(srcObj1, "$.students", "studentMobile", HideTool.MOBILE);
srcObj1 = HideTool.doHide(srcObj1, "$.students", "studentName", HideTool.NAME);
System.out.println("方式1脫敏後效果↓");
System.out.println(JSON.toJSONString(srcObj1));
//使用方式2,在map中批量指定屬性和稅敏方式,一次性轉換,性能較高
Object srcObj2 = JSONObject.parse(data);
Map map = new HashMap<String, String>();
map.put("studentMobile", HideTool.MOBILE);
map.put("studentName", HideTool.NAME);
Object hideResult2 = HideTool.doHide(srcObj2, "$.students", map);
System.out.println("方式2脫敏後效果↓");
System.out.println(JSON.toJSONString(hideResult2));
}
/**
* 脫敏目標對象是指定路徑的某一個鍵值
*
* @param srcObject 原始對象
* @param path jsonPath路徑
* @param key 屬性名, 鍵名
* @param type 隱藏類型
* @return
*/
public static Object doHide(Object srcObject, String path, String key, String type) {
Map map = new HashMap<String, String>();
map.put(key, type);
return doHide(srcObject, path, map);
}
/**
* 脫敏目標對象是指定路徑的某一批鍵值
*
* @param srcObject 原始對象
* @param path jsonPath路徑
* @param kv map.put("mobile", HideTool.MOBILE);map.put("name", HideTool.NAME);
* @return
*/
public static Object doHide(Object srcObject, String path, Map<String, String> kv) {
JSONObject targetObj;//目標對象
if (srcObject instanceof JSONObject) {
targetObj = (JSONObject) srcObject;
} else {
final String jsonString = JSON.toJSONString(srcObject);
targetObj = JSON.parseObject(jsonString);
}
final int dataSize = JSONPath.size(targetObj, path);
if (dataSize >= 1) {
Object dataObj = JSONPath.eval(targetObj, path);
if (dataObj instanceof List) {
for (Object obj : (List) dataObj) {
JSONObject o1 = (JSONObject) obj;
for (Map.Entry<String, String> entry : kv.entrySet()) {
String value1 = o1.getOrDefault(entry.getKey(), "").toString();
value1 = hideDetail(value1, entry.getValue());
o1.put(entry.getKey(), value1);
}
}
} else {
JSONObject o1 = (JSONObject) dataObj;
for (Map.Entry<String, String> entry : kv.entrySet()) {
String value1 = o1.getOrDefault(entry.getKey(), "").toString();
value1 = hideDetail(value1, entry.getValue());
o1.put(entry.getKey(), value1);
}
}
//System.out.println(JSON.toJSONString(dataObj));
}
return targetObj;
}
/**
* 脫敏詳情
*
* @param value 原值
* @param type 脫敏類型
* @return
*/
private static String hideDetail(String value, String type) {
switch (type) {
case "idcard":
value = StrUtil.hide(value, 5, 16);
break;
case "mobile":
value = StrUtil.hide(value, 3, 7);
break;
case "name":
if (value.length() <= 2) {
value = StrUtil.hide(value, 1, value.length());
} else {
value = StrUtil.hide(value, 1, value.length() - 1);
}
break;
default:
throw new RuntimeException("非法脫敏類型");
}
return value;
}
}
執行結果
方式1脫敏後效果↓
{"teacher":{"name":"王老師","id":"t0001","age":24},"students":[{"updateDate":"2022-08-16 16:37:21","studentName":"胡*","studentMobile":"137****5678","id":"s0001","createDate":"2022-08-16 16:37:21"},{"updateDate":"2022-08-17 16:37:21","studentName":"張*愛","studentMobile":"137****4321","id":"s0002","createDate":"2022-08-17 16:37:21"}]}
方式2脫敏後效果↓
{"teacher":{"name":"王老師","id":"t0001","age":24},"students":[{"updateDate":"2022-08-16 16:37:21","studentName":"胡*","studentMobile":"137****5678","id":"s0001","createDate":"2022-08-16 16:37:21"},{"updateDate":"2022-08-17 16:37:21","studentName":"張*愛","studentMobile":"137****4321","id":"s0002","createDate":"2022-08-17 16:37:21"}]}
最終studentName和studentMobile都按各自方式實現了脫敏處理.
優缺點
該工具類實現對象的脫敏非常方便 ,
使用方式1, 直接指定屬性和脫敏方式, 串行轉換, 性能較低, 但是可以對不同節點下的屬性值一點點脫敏
使用方式2, 在map中批量指定屬性和稅敏方式, 一次性轉換, 性能較高, 但是隻能對同一節點下的一批屬性值脫敏