最近在开始写【spring源码深度解析】系列文章,如果有对spring源码感兴趣的同学,欢迎点击左上角我的头像,查看相关文章,该系列文章均是结合我当时学习源码的经历编写完成,不是一上来就堆砌源码,而是从日常使用展开学习,力求让初学者弄懂spring相关模块的实现
在我们平时开发java企业项目,尤其是web项目时,返回给前端的数据中,许多敏感数据要进行脱敏处理,譬如手机号,银行卡号,身份证等,一般都会抽成一个util类来处理脱敏逻辑,之前看过一篇【递归对JSONObject每一个值进行加密操作】的博客,稍稍拓展了下,用在了项目中,下面分享给大家
package com.corleone.util;
import com.alibaba.fastjson.JSON;
import org.springframework.util.StringUtils;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;
public class SensitiveDataSolveUtil {
/**
* 脱敏方法入口
* @param data 要脱敏的数据,必须为list,map,实体类中的一种
* @param sensitiveColumn 要加密的字段
*/
public static Object encodeSensitiveData(Object data, String... sensitiveColumn){
if (data==null || sensitiveColumn.length==0){
return data;
}
//先转化为json对象
JSON rawJson = (JSON) JSON.toJSON(data);
List<String> sensitiveColumnList= Arrays.asList(sensitiveColumn);
dealWithRecursion(sensitiveColumnList,null,rawJson);
return JSON.parseObject(rawJson.toString(), data.getClass());
}
private static Object dealWithRecursion(List<String> sensitiveColumnList,String key,Object object) {
//为JsonObject
if (object instanceof Map) {
Map jsonObject = (Map) object;
Set keySet = jsonObject.keySet();
for (Object o : keySet) {
if (jsonObject.get(o) instanceof Map) {
Map ooo = (Map) jsonObject.get(o);
if (ooo==null) {
jsonObject.put(o, null);
} else {
dealWithRecursion(sensitiveColumnList,o.toString(),jsonObject.get(o));
}
} else if (jsonObject.get(o) instanceof List) {
dealWithRecursion(sensitiveColumnList,o.toString(),jsonObject.get(o));
} else {
jsonObject.put(o, encodeSensitiveDataMap(o.toString(),jsonObject.get(o),sensitiveColumnList));
}
}
return jsonObject;
} else if (object instanceof List) {
//为JsonArray
List<Object> list = new ArrayList<>();
List jsonArray = (List) object;
for (Object o : jsonArray) {
list.add(dealWithRecursion(sensitiveColumnList,key,o));
}
return list;
} else {
return encodeSensitiveDataMap(key,object,sensitiveColumnList);
}
}
//处理单个json的map
private static Object encodeSensitiveDataMap(String key,Object value, List<String> sensitiveColumnList) {
if (sensitiveColumnList.contains(key)){
return encodeNumber(value);
}
return value;
}
//加密数据
public static Object encodeNumber(Object data){
if (data==null){
return data;
}
String number=data.toString();
if (StringUtils.isEmpty(number)){
return data;
}
//这里加密方式比较简单粗暴,可以采用commonDisplay方法
if (number.length()<7){
return "****";
}
return number.substring(0,3)+"****"+number.substring(number.length()-4);
}
private static final int SIZE = 6;
private static final String SYMBOL = "*";
/**
* 通用脱敏方法
* @param value
* @return
*/
public static String commonDisplay(String value) {
if (null == value || "".equals(value)) {
return value;
}
int len = value.length();
int pamaone = len / 2;
int pamatwo = pamaone - 1;
int pamathree = len % 2;
StringBuilder stringBuilder = new StringBuilder();
if (len <= 2) {
if (pamathree == 1) {
return SYMBOL;
}
stringBuilder.append(SYMBOL);
stringBuilder.append(value.charAt(len - 1));
} else {
if (pamatwo <= 0) {
stringBuilder.append(value.substring(0, 1));
stringBuilder.append(SYMBOL);
stringBuilder.append(value.substring(len - 1, len));
} else if (pamatwo >= SIZE / 2 && SIZE + 1 != len) {
int pamafive = (len - SIZE) / 2;
stringBuilder.append(value.substring(0, pamafive));
for (int i = 0; i < SIZE; i++) {
stringBuilder.append(SYMBOL);
}
if ((pamathree == 0 && SIZE / 2 == 0) || (pamathree != 0 && SIZE % 2 != 0)) {
stringBuilder.append(value.substring(len - pamafive, len));
} else {
stringBuilder.append(value.substring(len - (pamafive + 1), len));
}
} else {
int pamafour = len - 2;
stringBuilder.append(value.substring(0, 1));
for (int i = 0; i < pamafour; i++) {
stringBuilder.append(SYMBOL);
}
stringBuilder.append(value.substring(len - 1, len));
}
}
return stringBuilder.toString();
}
/**
* 把data里所有带*的成员变量全部设置为null,这样如果dao层用的是updateByPrimaryKeySelective的方法,为空的字段就不会保存到数据库
* @param data
*/
public static void decodeSensitiveData(Object data){
try {
for (Field declaredField : data.getClass().getDeclaredFields()) {
declaredField.setAccessible(true);
Object fieldData=declaredField.get(data);
if (fieldData instanceof String){
String fieldDataStr=fieldData.toString();
if (!StringUtils.isEmpty(fieldDataStr)&&fieldDataStr.contains("*")) {
declaredField.set(data,null);
}
}
}
}catch (IllegalAccessException e){
e.printStackTrace();
}
}
//下面为测试代码
public static void main(String[] args) {
Map<String,String> map=new HashMap<>();
map.put("phone","12312345678");
map.put("name","jack");
//打印{phone=123****5678, name=jack}
System.out.println(encodeSensitiveData(map,"phone"));
List<Map<String,String>> list=new ArrayList<>();
list.add(map);
list.add(map);
//打印[{"phone":"123****5678","name":"jack"}, {"phone":"123****5678","name":"jack"}]
System.out.println(encodeSensitiveData(list,"phone"));
User user=new User();
user.setIdcard("78787878787878");
user.setPhone("12312345678");
//打印User{phone='123****5678', idcard='787****7878'}
System.out.println(encodeSensitiveData(user,"phone","idcard"));
}
static class User{
private String phone;
private String idcard;
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getIdcard() {
return idcard;
}
public void setIdcard(String idcard) {
this.idcard = idcard;
}
@Override
public String toString() {
return "User{" +
"phone='" + phone + '\'' +
", idcard='" + idcard + '\'' +
'}';
}
}
}