fastjson处理脱敏中的指定字段值[原]
需求
假如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中批量指定属性和税敏方式, 一次性转换, 性能较高, 但是只能对同一节点下的一批属性值脱敏
感觉空虚寂寞,只是因为你无所关注,无处付出。