敏感信息屏蔽工具

package com.pay.trade.util;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.pay.trade.annoation.Desensitized;
import com.pay.trade.constant.SensitiveMap;
import com.pay.trade.enums.SensitiveType;

/**
 * 
 * 敏感信息屏蔽工具
 */
public final class SensitiveInfoUtils {

    private static Logger logger = LoggerFactory.getLogger(SensitiveInfoUtils.class);

    private static final String NULLSTR = "null";

    /**
     * [中文姓名] 只显示第一个汉字,其他隐藏为星号<例子:李**>
     * 
     * @param name
     * @return
     */
    public static String chineseName(String fullName) {
        if (StringUtils.isBlank(fullName)) {
            return fullName;
        }
        String name = StringUtils.left(fullName, 1);
        return StringUtils.rightPad(name, 2, "*");
    }

    /**
     * [证件号码类](身份证,军官证,护照等身份证明证件类) 后8位用******(6个*)代替。不足8位,直接******(6个*)代替
     * 
     * @param id
     * @return
     */
    public static String idCardNum(String id) {
        if (StringUtils.isBlank(id)) {
            return id;
        }
        if (id.length() > 8) {
            return id.replaceAll(StringUtils.right(id, 8), "******");
        }
        return "******";
    }

    /**
     * [固定电话] 后四位,其他隐藏<例子:****1234>
     * 
     * @param num
     * @return
     */
    public static String fixedPhone(String phone) {
        if (StringUtils.isBlank(phone)) {
            return phone;
        }
        if (phone.length() > 4) {
            return StringUtils.leftPad(StringUtils.right(phone, 4), StringUtils.length(phone), "*");
        }
        return "******";
    }

    /**
     * [手机号码类](联系人电话,个人手机) 前3位显示,后4位显示,中间部分******(6个*)代替 不足7位直接******(6个*)代替
     * 
     * @param num
     * @return
     */
    public static String mobilePhone(String phone) {
        if (StringUtils.isBlank(phone)) {
            return phone;
        }
        if (phone.length() > 7) {
            return StringUtils.left(phone, 3) + "******" + (StringUtils.right(phone, 4));
        }
        return "******";
    }

    /**
     * 【地址】只显示到地区,不显示详细地址,比如:北京市海淀区****
     *
     * @param address
     * @param sensitiveSize
     *            敏感信息长度
     * @return
     */
    public static String address(String address, int sensitiveSize) {
        if (StringUtils.isBlank(address)) {
            return "";
        }
        int length = StringUtils.length(address);
        return StringUtils.rightPad(StringUtils.left(address, length - sensitiveSize), length, "*");
    }

    /**
     * [地址类] 前2位显示 ,后2位显示,中间部分******(6个*)代替 不足4位全部******(6个*)代替
     * 
     * @param address
     * @return
     */
    public static String address(String address) {
        if (StringUtils.isBlank(address)) {
            return address;
        }
        if (address.length() > 4) {
            return StringUtils.left(address, 2) + "******" + StringUtils.right(address, 2);
        }
        return "******";
    }

    /**
     * [邮箱类]******.com / (.)号之前全部******(6个*)代替,(.)号之后显示出来
     * 
     * @param email
     * @return
     */
    public static String email(String email) {
        if (StringUtils.isBlank(email)) {
            return email;
        }
        int index = email.lastIndexOf(".");
        if (index > 1) {
            return "******" + StringUtils.right(email, email.length() - index);
        }
        return "******";
    }

    /**
     * [卡号 ] 前2位显示,后4位显示,中间部分******(6个*)代替
     * 
     * @param cardNum
     * @return
     */
    public static String bankCard(String cardNum) {
        if (StringUtils.isBlank(cardNum)) {
            return cardNum;
        }
        if (cardNum.length() > 6) {
            return StringUtils.left(cardNum, 2) + "******" + StringUtils.right(cardNum, 4);
        }
        return "******";
    }

    /**
     * [银行名] 显示前4位
     * 
     * @param bankName
     * @return
     */
    public static String bankName(String bankName) {
        if (StringUtils.isBlank(bankName)) {
            return bankName;
        }
        if (bankName.length() > 4) {
            return StringUtils.rightPad(StringUtils.left(bankName, 4), StringUtils.length(bankName), "*");
        }
        return StringUtils.rightPad(StringUtils.left(bankName, 1), StringUtils.length(bankName), "*");
    }

    /**
     * [统一社会信用代码类(注册码,营业执照,牌照类的码) ] 前4位显示,后4位显示,中间部分******(6个*)代替
     * 
     * @param code
     * @return
     */
    public static String cnapsCode(String code) {
        if (StringUtils.isBlank(code)) {
            return code;
        }
        if (code.length() > 8) {
            return StringUtils.left(code, 4) + "******" + StringUtils.right(code, 4);
        }
        return "******";
    }

    /**
     * [银行卡有效期] 前1位,后1位,其他隐藏<例子:“0**6”>
     * 
     * @param num
     * @return
     */
    public static String cardValidDate(String date) {
        if (StringUtils.isBlank(date)) {
            return date;
        }
        return StringUtils.left(date, 1).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(date, 1), StringUtils.length(date), "*"), "*"));
    }

    /**
     * 全部隐藏
     * 
     * @param num
     * @return
     */
    public static String all(String data, int sensitiveSize) {
        return StringUtils.repeat("*", sensitiveSize);
    }

    /**
     * 根据信息类型屏蔽<br>
     * 
     * @param type
     *            信息类型
     * @param key
     *            信息key 如bankaccountno
     * @param value
     *            信息value 如 62121212312312
     * @return
     */
    public static String convertMsg(SensitiveType type, String value) {
        if (StringUtils.isBlank(value)) {
            return "";
        }
        // 返回null 时保持原样返回方便查问题
        if (NULLSTR.equalsIgnoreCase(value)) {
            return value;
        }
        switch (type) {
        case CHINESE_NAME: {
            value = SensitiveInfoUtils.chineseName(value);
            break;
        }
        case ID_CARD: {
            value = SensitiveInfoUtils.idCardNum(value);
            break;
        }
        case FIXED_PHONE: {
            value = SensitiveInfoUtils.fixedPhone(value);
            break;
        }
        case MOBILE_PHONE: {
            value = SensitiveInfoUtils.mobilePhone(value);
            break;
        }
        case ADDRESS: {
            value = SensitiveInfoUtils.address(value);
            break;
        }
        case EMAIL: {
            value = SensitiveInfoUtils.email(value);
            break;
        }
        case BANK_CARD: {
            value = SensitiveInfoUtils.bankCard(value);
            break;
        }
        case BANK_NAME: {
            value = SensitiveInfoUtils.bankName(value);
            break;
        }
        case CNAPS_CODE: {
            value = SensitiveInfoUtils.cnapsCode(value);
            break;
        }
        case BANK_CARD_DATE: {
            value = SensitiveInfoUtils.cardValidDate(value);
            break;
        }
        case PASSWORD: {
            value = SensitiveInfoUtils.all(value, 6);
            break;
        }
        case ALL: {
            value = SensitiveInfoUtils.all(value, 3);
            break;
        }
        case NULL: {
            value = null;
            break;
        }
        default:
            break;
        }
        return value;
    }

    /**
     * 对bean对象转换成脱敏后的对象
     * 
     * @param javaBean
     * @throws Exception
     */
    public static void processObject(Object javaBean) throws Exception {
        if (javaBean == null) {
            return;
        }
        if (javaBean.getClass().isInterface()) {
            return;
        }
        /* 定义一个计数器,用于避免重复循环自定义对象类型的字段 */
        Set<Integer> referenceCounter = new HashSet<Integer>();
        /* 对克隆实体进行脱敏操作 */
        replace(getAllFields(javaBean), javaBean, referenceCounter);
        /* 清空计数器 */
        referenceCounter.clear();
        referenceCounter = null;
    }

    /**
     * 对bean字符串输出
     * 
     * @param javaBean
     * @return
     * @throws Exception
     */
    public static String getObjectStr(Object javaBean) {
        if (javaBean == null) {
            logger.debug("javaBean is null");
            return null;
        }
        if (javaBean.getClass().isInterface()) {
            logger.debug("javaBean is interface");
            return null;
        }
        Set<Integer> referenceCounter = new HashSet<Integer>();
        try {
            StringBuilder sb = new StringBuilder();
            sb.append(javaBean.getClass().getSimpleName()).append(" [");
            getFiledStr(getAllFields(javaBean), javaBean, referenceCounter, sb);
            sb.append("]");
            return sb.toString().replaceAll(", ]", "]");
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 对需要脱敏的字段进行转化
     *
     * @param fields
     * @param javaBean
     * @param referenceCounter
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     */
    private static void replace(Field[] fields, Object javaBean, Set<Integer> referenceCounter) throws IllegalArgumentException, IllegalAccessException {
        if (null != fields && fields.length > 0) {
            for (Field field : fields) {
                field.setAccessible(true);
                if (null != field && null != javaBean) {
                    Object value = field.get(javaBean);
                    if (null != value) {
                        Class<?> type = value.getClass();
                        // 处理子属性,包括集合中的
                        if (type.isArray()) {// 对数组类型的字段进行递归过滤
                            int len = Array.getLength(value);
                            for (int i = 0; i < len; i++) {
                                Object arrayObject = Array.get(value, i);
                                if (arrayObject == null) {
                                    continue;
                                }
                                if (isNotGeneralType(arrayObject.getClass(), arrayObject, referenceCounter)) {
                                    replace(getAllFields(arrayObject), arrayObject, referenceCounter);
                                }
                            }
                        } else if (value instanceof Collection<?>) {// 对集合类型的字段进行递归过滤
                            Collection<?> c = (Collection<?>) value;
                            Iterator<?> it = c.iterator();
                            while (it.hasNext()) {// TODO: 待优化
                                Object collectionObj = it.next();
                                if (collectionObj == null) {
                                    continue;
                                }
                                if (isNotGeneralType(collectionObj.getClass(), collectionObj, referenceCounter)) {
                                    replace(getAllFields(collectionObj), collectionObj, referenceCounter);
                                }
                            }
                        } else if (value instanceof Map<?, ?>) {// 对Map类型的字段进行递归过滤
                            Map<?, ?> m = (Map<?, ?>) value;
                            Set<?> set = m.entrySet();
                            if (set == null) {
                                continue;
                            }
                            for (Object o : set) {
                                Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
                                Object mapVal = entry.getValue();
                                if (mapVal == null) {
                                    continue;
                                }
                                if (isNotGeneralType(mapVal.getClass(), mapVal, referenceCounter)) {
                                    replace(getAllFields(mapVal), mapVal, referenceCounter);
                                }
                            }
                        } else if (value instanceof Enum<?>) {
                            continue;
                        }
                        /* 除基础类型、jdk类型的字段之外,对其他类型的字段进行递归过滤 */
                        else {
                            if (!type.isPrimitive() && type.getPackage() != null && !StringUtils.startsWith(type.getPackage().getName(), "javax.")
                                    && !StringUtils.startsWith(type.getPackage().getName(), "java.")
                                    && !StringUtils.startsWith(field.getType().getName(), "javax.") && !StringUtils.startsWith(field.getName(), "java.")
                                    && referenceCounter.add(value.hashCode())) {
                                replace(getAllFields(value), value, referenceCounter);
                            }
                        }
                    }
                    // 脱敏操作
                    setNewValueForField(javaBean, field, value);
                }
            }
        }
    }

    /**
     * 脱敏操作(按照规则转化需要脱敏的字段并设置新值) 目前只支持String类型的字段,如需要其他类型如BigDecimal、Date等类型,可以添加
     *
     * @param javaBean
     * @param field
     * @param value
     * @throws IllegalAccessException
     */
    private static void setNewValueForField(Object javaBean, Field field, Object value) throws IllegalAccessException {
        // 处理自身的属性
        Desensitized annotation = field.getAnnotation(Desensitized.class);
        if (field.getType().equals(String.class) && null != annotation && executeIsEffictiveMethod(javaBean, annotation)) {
            String valueStr = (String) value;
            if (StringUtils.isNotBlank(valueStr)) {
                field.set(javaBean, SensitiveInfoUtils.convertMsg(annotation.type(), valueStr));
            }
        }
    }

    /**
     * 执行某个对象中指定的方法
     *
     * @param javaBean
     *            对象
     * @param desensitized
     * @return
     */
    private static boolean executeIsEffictiveMethod(Object javaBean, Desensitized desensitized) {
        boolean isAnnotationEffictive = true;// 注解默认生效
        if (desensitized != null) {
            String isEffictiveMethod = desensitized.isEffictiveMethod();
            if (StringUtils.isNotBlank(isEffictiveMethod)) {
                try {
                    Method method = javaBean.getClass().getMethod(isEffictiveMethod);
                    method.setAccessible(true);
                    isAnnotationEffictive = (Boolean) method.invoke(javaBean);
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
        return isAnnotationEffictive;
    }

    /**
     * 排除基础类型、jdk类型、枚举类型的字段
     *
     * @param clazz
     * @param value
     * @param referenceCounter
     * @return
     */
    private static boolean isNotGeneralType(Class<?> clazz, Object value, Set<Integer> referenceCounter) {
        return !clazz.isPrimitive() && clazz.getPackage() != null && !clazz.isEnum() && !StringUtils.startsWith(clazz.getPackage().getName(), "javax.")
                && !StringUtils.startsWith(clazz.getPackage().getName(), "java.") && !StringUtils.startsWith(clazz.getName(), "javax.")
                && !StringUtils.startsWith(clazz.getName(), "java.") && referenceCounter.add(value.hashCode());
    }

    /**
     * 获取包括父类所有的属性
     *
     * @param objSource
     * @return
     */
    private static Field[] getAllFields(Object objSource) {
        /* 获得当前类的所有属性(private、protected、public) */
        List<Field> fieldList = new ArrayList<Field>();
        Class<?> tempClass = objSource.getClass();
        while (tempClass != null && !tempClass.getName().toLowerCase().equals("java.lang.object")) {// 当父类为null的时候说明到达了最上层的父类(Object类).
            fieldList.addAll(Arrays.asList(tempClass.getDeclaredFields()));
            tempClass = tempClass.getSuperclass(); // 得到父类,然后赋给自己
        }
        Field[] fields = new Field[fieldList.size()];
        fieldList.toArray(fields);
        return fields;
    }

    /**
     * 获取包括父类所有的属性
     *
     * @param objSource
     * @param sb
     * @return
     * @throws IllegalAccessException
     * @throws IllegalArgumentException
     */
    private static String getFiledStr(Field[] fields, Object objSource, Set<Integer> referenceCounter, StringBuilder sb)
            throws IllegalArgumentException, IllegalAccessException {
        /* 获得当前类的所有属性(private、protected、public) */
        if (null != fields && fields.length > 0) {
            for (Field field : fields) {
                field.setAccessible(true);
                if (null != field && null != objSource) {
                    Object value = field.get(objSource);
                    if (null != value) {
                        Class<?> type = value.getClass();
                        // 处理子属性,包括集合中的
                        if (type.isArray()) {// 对数组类型的字段进行递归过滤
                            Desensitized annotation = field.getAnnotation(Desensitized.class);
                            if (annotation != null) {
                                sb.append(field.getName()).append(" = [ *** ]");
                            } else {
                                int len = Array.getLength(value);
                                sb.append(field.getName()).append(" = [");
                                for (int i = 0; i < len; i++) {
                                    Object arrayObject = Array.get(value, i);
                                    if (arrayObject == null) {
                                        continue;
                                    }
                                    sb.append(arrayObject.getClass().getSimpleName()).append(" [");
                                    if (isNotGeneralType(arrayObject.getClass(), arrayObject, referenceCounter)) {
                                        getFiledStr(getAllFields(arrayObject), arrayObject, referenceCounter, sb);
                                    } else {
                                        getFieldStr(objSource, field, value, sb);
                                    }
                                    sb.append("], ");
                                }
                                sb.append("], ");
                            }
                        } else if (value instanceof Collection<?>) {// 对集合类型的字段进行递归过滤
                            Desensitized annotation = field.getAnnotation(Desensitized.class);
                            if (annotation != null) {
                                sb.append(field.getName()).append(" = [ *** ]");
                            } else {
                                Collection<?> c = (Collection<?>) value;
                                Iterator<?> it = c.iterator();
                                sb.append(field.getName()).append(" = [");
                                while (it.hasNext()) {// TODO: 待优化
                                    Object collectionObj = it.next();
                                    if (collectionObj == null) {
                                        continue;
                                    }
                                    sb.append(collectionObj.getClass().getSimpleName()).append(" [");
                                    if (isNotGeneralType(collectionObj.getClass(), collectionObj, referenceCounter)) {
                                        getFiledStr(getAllFields(collectionObj), collectionObj, referenceCounter, sb);
                                    } else {
                                        getFieldStr(objSource, field, value, sb);
                                    }
                                    sb.append("], ");
                                }
                                sb.append("], ");
                            }
                        } else if (value instanceof Map<?, ?>) {// 对Map类型的字段进行递归过滤
                            Map<?, ?> m = (Map<?, ?>) value;
                            Set<?> set = m.entrySet();
                            if (set == null) {
                                continue;
                            }
                            Desensitized annotation = field.getAnnotation(Desensitized.class);
                            if (annotation != null) {
                                sb.append(field.getName()).append(" = [ *** ]");
                            } else {
                                sb.append(field.getName()).append(" = [");
                                for (Object o : set) {
                                    Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
                                    Object mapVal = entry.getValue();
                                    if (mapVal == null) {
                                        continue;
                                    }
                                    sb.append(entry.getKey()).append(" = ").append(mapVal.getClass().getSimpleName()).append(" [");
                                    if (isNotGeneralType(mapVal.getClass(), mapVal, referenceCounter)) {
                                        getFiledStr(getAllFields(mapVal), mapVal, referenceCounter, sb);
                                    } else {
                                        getFieldStr(objSource, field, value, sb);
                                    }
                                    sb.append("], ");
                                }
                                sb.append("], ");
                            }
                        } else if (value instanceof Enum<?>) {
                            continue;
                        } else if (!type.isPrimitive() && type.getPackage() != null && !StringUtils.startsWith(type.getPackage().getName(), "javax.")
                                && !StringUtils.startsWith(type.getPackage().getName(), "java.") && !StringUtils.startsWith(field.getType().getName(), "javax.")
                                && !StringUtils.startsWith(field.getName(), "java.") && referenceCounter.add(value.hashCode())) {
                            Desensitized annotation = field.getAnnotation(Desensitized.class);
                            if (annotation != null) {
                                sb.append(field.getName()).append("=").append(type.getSimpleName()).append(" [ *** ]");
                            } else {
                                sb.append(field.getName()).append("=").append(type.getSimpleName()).append(" [");
                                getFiledStr(getAllFields(value), value, referenceCounter, sb);
                                sb.append("], ");
                            }
                        } else {
                            // 脱敏操作
                            getFieldStr(objSource, field, value, sb);
                        }
                    }
                }
            }
        }
        return sb.toString();
    }

    private static void getFieldStr(Object objSource, Field field, Object value, StringBuilder sb) {
        // 处理自身的属性
        Desensitized annotation = field.getAnnotation(Desensitized.class);
        if (field.getType().equals(String.class) && null != annotation && executeIsEffictiveMethod(objSource, annotation)) {
            String valueStr = (String) value;
            if (StringUtils.isNotBlank(valueStr)) {
                sb.append(field.getName()).append(" = ").append(SensitiveInfoUtils.convertMsg(annotation.type(), valueStr)).append(", ");
            } else {
                sb.append(field.getName()).append(" = null, ");
            }
        } else {
            if (SensitiveMap.getSensitiveMap().containsKey(field.getName())) {
                sb.append(field.getName()).append(" = ")
                        .append(SensitiveInfoUtils.convertMsg(SensitiveMap.getSensitiveMap().get(field.getName()), value == null ? null : value.toString()))
                        .append(", ");
            } else {
                sb.append(field.getName()).append(" = ").append(value).append(", ");
            }
        }
    }
}

 

posted @ 2021-08-03 20:28  唉我头发呢  阅读(130)  评论(0)    收藏  举报
Live2D