简单易用的java项目通用的返回对象数据脱敏(加密)工具类

最近在开始写【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 + '\'' +
                    '}';
        }
    }
}

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值