精华内容
下载资源
问答
  • Java脱敏工具类

    2020-12-25 15:51:07
    就是关键信息需要脱敏处理 设想是在网关的response拦截里对需要拦截的接口、需要脱敏的属性值进行统一处理 拦截的接口和属性配置到nacos的网关配置中 import java.util.HashMap; /** * 关键字脱敏规则 * @date ...

    前言:

    好像没有什么要描述的…
    就是关键信息需要脱敏处理
    设想是在网关的response拦截里对需要拦截的接口需要脱敏的属性值进行统一处理
    拦截的接口和属性配置到nacos的网关配置中

    import java.util.HashMap;
    
    /**
     * 关键字脱敏规则
     * @date 2020/12/25 10:23
     * @author wei.heng
     */
    public class KeyWordPatterns extends HashMap<String, String> {
    
    	/**
    	 * 增加脱敏规则
    	 * @param key 需要做脱敏处理的字段 - 与入参,对象属性名或map的key 能做equals匹配
    	 * @param pattern 脱敏规则,如:3-6(第四个字符到第六个字符,进行模糊处理,替换为*号)
    	 * @date 2020/12/25 11:28
    	 * @author wei.heng
    	 */
    	public void addPattern(String key, String pattern){
    		super.put(key, pattern);
    	};
    }
    
    
    
    /**
     *
     * 关键信息脱敏规则异常
     * @date 2020/12/25 11:41
     * @author wei.heng
     */
    public class UnsupportedKeyWordsPattern extends RuntimeException {
    
    	private static final long serialVersionUID = 1L;
    
    	private Integer code = HttpStatus.ERROR;
    
    	private String message = "脱敏规则配置有误";
    
    	public UnsupportedKeyWordsPattern() {
    	}
    
    	public Integer getCode() {
    		return code;
    	}
    
    	public void setCode(Integer code) {
    		this.code = code;
    	}
    
    	@Override
    	public String getMessage() {
    		return message;
    	}
    
    	public void setMessage(String message) {
    		this.message = message;
    	}
    }
    
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import java.lang.reflect.Field;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    import java.util.regex.Pattern;
    
    /**
     * 关键信息脱敏处理
     * 设计思路:nacos的网关里配置需要拦截的接口,需要脱敏的属性值,注入到代码中,再以参数形式使用该脱敏工具类进行统一处理
     * 个人感觉这样会比较灵活
     * @author wei.heng
     * @date 2020/12/25 10:15
     */
    public class KeyWordsFilterUtil {
    
    	private Logger log = LoggerFactory.getLogger(this.getClass());
    
    	/** 脱敏数据类型 */
    	private final String CAN_BE_MODIFY_TYPE = "String";
    	/** 用于替换敏感信息的字符 */
    	private final String REPLACE_CHAR = "*";
    
    	public void filter(Object data, KeyWordPatterns patterns) {
    		if (data instanceof List) {
    			List<Object> list = (List) data;
    			for (Object o : list) {
    				filter(o, patterns);
    			}
    		} else if (data instanceof Map) {
    			// 不推荐接口间交互以map的形式
    			resetMapValue((Map) data, patterns);
    		} else {
    			resetObjectProperties(data, patterns);
    		}
    	}
    
    	/**
    	 *
    	 * 重设map里需要模糊处理的value值
    	 * @param data map数据对象
    	 * @param patterns 模糊匹配规则
    	 * @date 2020/12/25 14:12
    	 * @author wei.heng
    	 */
    	private void resetMapValue(Map data, KeyWordPatterns patterns) {
    		Set<String> filterKeys = patterns.keySet();
    		Map<String, Object> map = data;
    		Set<String> objKeys = map.keySet();
    		for (String objKey : objKeys) {
    			if(!filterKeys.contains(objKey)){
    				continue;
    			}
    			Object objValue = map.get(objKey);
    			if(objValue instanceof String){
    				String replacedStr = getReplacedString(patterns.get(objKey), objValue.toString());
    				// 用模糊处理后的数据,覆盖原有值
    				map.put(objKey, replacedStr);
    			} else {
    				// 当做对象进行处理
    				resetObjectProperties(objValue, patterns);
    			}
    		}
    	}
    
    	/**
    	 *
    	 * 重设对象需要模糊处理的属性值
    	 * @param data 数据对象
    	 * @param patterns 模糊处理匹配规则
    	 * @date 2020/12/25 14:12
    	 * @author wei.heng
    	 */
    	private void resetObjectProperties(Object data, KeyWordPatterns patterns) {
    
    		if(data == null){
    			return;
    		}
    
    		// 取需要过滤的关键字key
    		Set<String> keys = patterns.keySet();
    		Class<?> clazz = data.getClass().getSuperclass();
    		Field[] fields = clazz.getDeclaredFields();
    		for (int i = 0; i < fields.length; i++) {
    			Field field = fields[i];
    			field.setAccessible(true);
    			// 获取对象属性名称
    			String attributeName = field.getName();
    			// 获取对象属性类型
    			String simpleName = field.getType().getSimpleName();
    			try {
    				// 是否复杂数据对象
    				Object valObj = field.get(data);
    				if(isComplexType(simpleName)) {
    					// 如果是复杂数据对象,执行递归操作
    					resetObjectProperties(valObj, patterns);
    				};
    				// 不是字符串,不做过滤
    				if (!CAN_BE_MODIFY_TYPE.equals(simpleName)) {
    					continue;
    				}
    				// 不属于要过滤的字段,不做过滤
    				if (!keys.contains(attributeName)) {
    					continue;
    				}
    				// 前面已做过类型判断了,走到这里必须是String类型
    				String valStr = valObj.toString();
    				String pattern = patterns.get(attributeName);
    				String replacedStr = getReplacedString(pattern, valStr);
    
    				field.set(data, replacedStr);
    			} catch (IllegalAccessException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    
    	/**
    	 *
    	 * 
    	 * @param pattern 脱敏规则,如:3-6(第四个字符到第六个字符,进行模糊处理,替换为*号)
    	 * @param valStr 需要做脱敏处理的字符串
    	 * @return java.lang.String
    	 * @date 2020/12/25 13:59
    	 * @author wei.heng
    	 */
    	private String getReplacedString(String pattern, String valStr) {
    
    		// 是否符合脱敏规则
    		final String regexPattern = "\\d+-\\d+";
    		boolean isMatch = Pattern.matches(regexPattern, pattern);
    		if(!isMatch){
    			// 不符合规则,不进行匹配
    			log.error("脱敏规则配置异常:{}", pattern);
    			throw new UnsupportedKeyWordsPattern();
    		}
    		String[] patternArr = pattern.split("-");
    		int startIndex = Integer.parseInt(patternArr[0]);
    		int endIndex = Integer.parseInt(patternArr[1]);
    		if(startIndex > endIndex){
    			log.error("脱敏规则配置异常:{}", pattern);
    			throw new UnsupportedKeyWordsPattern();
    		}
    		int replaceLength = endIndex - startIndex;
    		String replaceStr = "*";
    		for (int j = 1; j < replaceLength; j++) {
    			replaceStr += REPLACE_CHAR;
    		}
    		return valStr.substring(0,startIndex) + replaceStr + valStr.substring(endIndex);
    	}
    
    	/**
    	 *
    	 * 是否复杂数据对象 - 该属性不是 int、byte、long、double、float、char、boolean、Decimal、String 类型
    	 * @param classSimpleName 数据类型
    	 * @date 2020/12/25 14:28
    	 * @author wei.heng
    	 */
    	public static boolean isComplexType(String classSimpleName) {
    		return !classSimpleName.equals("int") &&
    			!classSimpleName.equals("Integer") &&
    			!classSimpleName.equals("Byte") &&
    			!classSimpleName.equals("byte") &&
    			!classSimpleName.equals("Long") &&
    			!classSimpleName.equals("long") &&
    			!classSimpleName.equals("Double") &&
    			!classSimpleName.equals("double") &&
    			!classSimpleName.equals("Float") &&
    			!classSimpleName.equals("float") &&
    			!classSimpleName.equals("Character") &&
    			!classSimpleName.equals("char") &&
    			!classSimpleName.equals("Short") &&
    			!classSimpleName.equals("short") &&
    			!classSimpleName.equals("Boolean") &&
    			!classSimpleName.equals("boolean") &&
    			!classSimpleName.equals("BigDecimal") &&
    			!classSimpleName.equals("Date") &&
    			!classSimpleName.equals("String");
    	}
    
    //	public static void main(String[] args) {
    //
    //		// 测试场景1 - object:
    //		AppUser appUser = new AppUser() {{
    //			setIdNumber("500225198810010011");
    //		}};
    //		new KeyWordsFilterUtil().filter(appUser, new KeyWordPatterns() {{
    //			addPattern("idNumber", "3-16");
    //		}});
    //		System.out.println("replacedInfo:" + JSON.toJSONString(appUser));
    //		// replacedInfo:{"idNumber":"500*************11"}
    //
    //		// 测试场景2 - List:
    //		AppUser appUser2 = new AppUser() {{
    //			setIdNumber("511225198810010011");
    //		}};
    //		List<AppUser> objects = new ArrayList<>();
    //		objects.add(appUser);
    //		objects.add(appUser2);
    //		new KeyWordsFilterUtil().filter(objects, new KeyWordPatterns() {{
    //			addPattern("idNumber", "3-16");
    //		}});
    //		System.out.println("replacedInfo2:" + JSON.toJSONString(objects));
    //		// replacedInfo2:[{"idNumber":"500*************11"},{"idNumber":"511*************11"}]
    //
    //		// 测试场景3 - 复杂对象
    //		appUser.setGasStudent(new GasStudent(){{
    //			setIdCard("500660198810010011");
    //		}});
    //		new KeyWordsFilterUtil().filter(objects, new KeyWordPatterns() {{
    //			addPattern("idNumber", "3-16");
    //			addPattern("idCard", "4-15");
    //		}});
    //		System.out.println("replacedInfo3:" + JSON.toJSONString(objects));
    //		//replacedInfo3:[{"gasStudent":{"idCard":"5006***********011"},"idNumber":"500*************11","sex":0},{"idNumber":"511*************11","sex":0}]
    //
    //		// 测试场景4 - jsonObject
    //		JSONObject jsonObj = (JSONObject)JSONObject.toJSON(appUser);
    //		new KeyWordsFilterUtil().filter(jsonObj, new KeyWordPatterns() {{
    //			addPattern("idNumber", "3-16");
    //			addPattern("idCard", "4-15");
    //		}});
    //		System.out.println("replacedInfo jsonObj:" + JSON.toJSONString(jsonObj));
    //		// replacedInfo jsonObj:{"idNumber":"500*************11","gasStudent":{"idCard":"5006***********011"}}
    //
    //		// 测试场景3 - map:
    //		// 这个不测了,不推荐走map参数...
    //	}
    
    }
    
    
    展开全文
  • 脱敏工具类

    千次阅读 2019-05-23 15:22:09
    实现脱敏处理: package com.ciip.cloud.core.usercenter.utils; import com.ciip.cloud.core.usercenter.config.aliyun.Desensitized; import org.springframework.data.domain.Page; import org.spring...

    实现脱敏处理类:

    package com.ciip.cloud.core.usercenter.utils;
    
    
    import com.ciip.cloud.core.usercenter.config.aliyun.Desensitized;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.PageImpl;
    import org.springframework.data.domain.PageRequest;
    import org.apache.commons.lang.StringUtils;
    
    import java.lang.reflect.Array;
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.*;
    
    
    /**
     * Title: DesensitizedUtils
     * Description: 实现脱敏处理类
     *
     * @author jintian
     * @created 2019/5/23 10:41
     */
    public class DesensitizedUtils {
    
        /**
         * 获取脱敏json串(递归引用会导致java.lang.StackOverflowError)
         *
         * @param javaBean
         * @return
         */
        public static Object getJson(Object javaBean) {
            String json = null;
            if (null != javaBean) {
                try {
                    if (javaBean.getClass().isInterface()) return json;
                    /* 定义一个计数器,用于避免重复循环自定义对象类型的字段 */
                    Set<Integer> referenceCounter = new HashSet<Integer>();
    
                    /* 对实体进行脱敏操作 */
                    DesensitizedUtils.replace(ObjectUtils.getAllFields(javaBean), javaBean, referenceCounter);
    
                    /* 清空计数器 */
                    referenceCounter.clear();
                    referenceCounter = null;
                } catch (Throwable e) {
                    e.printStackTrace();
                }
            }
            return javaBean;
        }
    
        /**
         * 对需要脱敏的字段进行转化
         *
         * @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 (isNotGeneralType(arrayObject.getClass(), arrayObject, referenceCounter)) {
                                        replace(ObjectUtils.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 (isNotGeneralType(collectionObj.getClass(), collectionObj, referenceCounter)) {
                                        replace(ObjectUtils.getAllFields(collectionObj), collectionObj, referenceCounter);
                                    }
                                }
                            } else if (value instanceof Map<?, ?>) {//对Map类型的字段进行递归过滤
                                Map<?, ?> m = (Map<?, ?>) value;
                                Set<?> set = m.entrySet();
                                for (Object o : set) {
                                    Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
                                    Object mapVal = entry.getValue();
                                    if (isNotGeneralType(mapVal.getClass(), mapVal, referenceCounter)) {
                                        replace(ObjectUtils.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(ObjectUtils.getAllFields(value), value, referenceCounter);
                                }
                            }
                        }
                        //脱敏操作
                        setNewValueForField(javaBean, field, value);
    
                    }
                }
            }
        }
    
        /**
         * 排除基础类型、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());
        }
    
        /**
         * 脱敏操作(按照规则转化需要脱敏的字段并设置新值)
         * 目前只支持String类型的字段,如需要其他类型如BigDecimal、Date等类型,可以添加
         *
         * @param javaBean
         * @param field
         * @param value
         * @throws IllegalAccessException
         */
        public 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)) {
                    switch (annotation.type()) {
                        case CHINESE_NAME: {
                            field.set(javaBean, DesensitizedUtils.chineseName(valueStr));
                            break;
                        }
                        case ID_CARD: {
                            field.set(javaBean, DesensitizedUtils.idCardNum(valueStr));
                            break;
                        }
                        case FIXED_PHONE: {
                            field.set(javaBean, DesensitizedUtils.fixedPhone(valueStr));
    
                            break;
                        }
                        case MOBILE_PHONE: {
                            field.set(javaBean, DesensitizedUtils.mobilePhone(valueStr));
                            break;
                        }
                        case ADDRESS: {
                            field.set(javaBean, DesensitizedUtils.address(valueStr, 8));
                            break;
                        }
                        case EMAIL: {
                            field.set(javaBean, DesensitizedUtils.email(valueStr));
                            break;
                        }
                        case BANK_CARD: {
                            field.set(javaBean, DesensitizedUtils.bankCard(valueStr));
                            break;
                        }
                        case PASSWORD: {
                            field.set(javaBean, DesensitizedUtils.password(valueStr));
                            break;
                        }
                    }
                }
            }
        }
    
        /**
         * 执行某个对象中指定的方法
         *
         * @param javaBean     对象
         * @param desensitized
         * @return
         */
        private static boolean executeIsEffictiveMethod(Object javaBean, Desensitized desensitized) {
            boolean isAnnotationEffictive = true;//注解默认生效
            if (desensitized != null) {
                String isEffictiveMethod = desensitized.isEffictiveMethod();
                if (isNotEmpty(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;
        }
    
        private static boolean isNotEmpty(String str) {
            return str != null && !"".equals(str);
        }
    
        private static boolean isEmpty(String str) {
            return !isNotEmpty(str);
        }
    
        /**
         * 【中文姓名】只显示第一个汉字,其他隐藏为2个星号,比如:李**
         *
         * @param fullName
         * @return
         */
        public static String chineseName(String fullName) {
            if (StringUtils.isBlank(fullName)) {
                return "";
            }
            String name = StringUtils.left(fullName, 1);
            return StringUtils.rightPad(name, StringUtils.length(fullName), "*");
        }
    
        /**
         * 【身份证号】显示最后四位,其他隐藏。共计18位或者15位,比如:*************1234,227172********1234
         *
         * @param id
         * @return
         */
        public static String idCardNum(String id) {
            if (StringUtils.isBlank(id)) {
                return "";
            }
    //        String num = StringUtils.right(id, 4);
    //        return StringUtils.leftPad(num, StringUtils.length(id), "*");
            return StringUtils.left(id, 6).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(id, 4), StringUtils.length(id), "*"), "******"));
        }
    
        /**
         * 【固定电话 后四位,其他隐藏,比如1234
         *
         * @param num
         * @return
         */
        public static String fixedPhone(String num) {
            if (StringUtils.isBlank(num)) {
                return "";
            }
            return StringUtils.leftPad(StringUtils.right(num, 4), StringUtils.length(num), "*");
        }
    
        /**
         * 【手机号码】前三位,后四位,其他隐藏,比如135****6810
         *
         * @param num
         * @return
         */
        public static String mobilePhone(String num) {
            if (StringUtils.isBlank(num)) {
                return "";
            }
            return StringUtils.left(num, 3).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(num, 4), StringUtils.length(num), "*"), "***"));
        }
    
        /**
         * 【地址】只显示到地区,不显示详细地址,比如:北京市海淀区****
         *
         * @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, "*");
        }
    
        /**
         * 【电子邮箱 邮箱前缀仅显示第一个字母,前缀其他隐藏,用星号代替,@及后面的地址显示,比如:d**@126.com>
         *
         * @param email
         * @return
         */
        public static String email(String email) {
            if (StringUtils.isBlank(email)) {
                return "";
            }
            int index = StringUtils.indexOf(email, "@");
            if (index <= 1)
                return email;
            else
                return StringUtils.rightPad(StringUtils.left(email, 1), index, "*").concat(StringUtils.mid(email, index, StringUtils.length(email)));
        }
    
        /**
         * 【银行卡号】前六位,后四位,其他用星号隐藏每位1个星号,比如:6222600**********1234>
         *
         * @param cardNum
         * @return
         */
        public static String bankCard(String cardNum) {
            if (StringUtils.isBlank(cardNum)) {
                return "";
            }
            return StringUtils.left(cardNum, 6).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(cardNum, 4), StringUtils.length(cardNum), "*"), "******"));
        }
    
        /**
         * 【密码】密码的全部字符都用*代替,比如:******
         *
         * @param password
         * @return
         */
        public static String password(String password) {
            if (StringUtils.isBlank(password)) {
                return "";
            }
            String pwd = StringUtils.left(password, 0);
            return StringUtils.rightPad(pwd, StringUtils.length(password), "*");
        }
    
        /**
         * 遍历page对数据脱敏
         * @param pageContent
         * @param page
         * @param size
         * @return
         */
    //    public static <T> Page desensitizedPage(Page<T> pageContent, int page, int size, Class tClass) {
    //        //获取page的内容
    //        List<T> content = pageContent.getContent();
    //        if (content == null || content.size() <= 0) {
    //            return pageContent;
    //        }
    //        //数据脱敏
    //        List list = desensitizedList(content,tClass);
    //        return new PageImpl(list, new PageRequest(page, size), pageContent.getTotalElements());
    //    }
    
        /**
         * 遍历List脱敏数据
         * @param content
         * @return
         */
    //    public static <T> List desensitizedList(List<T> content,Class tClass){
    //        if (content == null || content.size() <= 0) {
    //            return content;
    //        }
    //        List list = new ArrayList<>();
    //        for (T t : content) {
    //            list.add(desensitizedObject(t,tClass));
    //        }
    //        return list;
    //    }
        /**
         * 对象脱敏
         * @param content
         * @return
         */
    //    public static <T> Object desensitizedObject(T content,Class tClass){
    //        if(content != null){
    //            try {
    //                Object o = tClass.newInstance();
    //                BeanCopyUtil.copyPropertiesIgnoreNull(content,o);
    //                return getJson(o);
    //            } catch (InstantiationException e) {
    //                e.printStackTrace();
    //            } catch (IllegalAccessException e) {
    //                e.printStackTrace();
    //            }
    //        }
    //        return null;
    //    }
    }
    

    ObjectUtils类:

    package com.ciip.cloud.core.usercenter.utils;
    
    import com.alibaba.fastjson.JSON;
    import org.apache.commons.io.output.ByteArrayOutputStream;
    import org.apache.commons.lang.StringUtils;
    
    import java.io.ByteArrayInputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.lang.reflect.Array;
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Modifier;
    import java.util.*;
    
    
    /**
     * Title: ObjectUtils
     * Description: TODO
     *
     * @author jintian
     * @created 2019/5/23 11:05
     */
    
    public class ObjectUtils {
        /**
         * 用序列化-反序列化方式实现深克隆
         * 缺点:1、被拷贝的对象必须要实现序列化
         *
         * @param obj
         * @return
         */
        @SuppressWarnings("unchecked")
        public static <T> T deepCloneObject(T obj) throws Exception {
            T t = (T) new Object();
            try {
                ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
                ObjectOutputStream out = new ObjectOutputStream(byteOut);
                out.writeObject(obj);
                out.close();
                ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
                ObjectInputStream in = new ObjectInputStream(byteIn);
                t = (T) in.readObject();
                in.close();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            return t;
        }
    
    
    
        /**
         * 用序列化-反序列化的方式实现深克隆
         * 缺点:1、当实体中存在接口类型的参数,并且这个接口指向的实例为枚举类型时,会报错"com.alibaba.fastjson.JSONException: syntax error, expect {, actual string, pos 171, fieldName iLimitKey"
         *
         * @param objSource
         * @return
         */
        public static Object deepCloneByFastJson(Object objSource) {
            String tempJson = JSON.toJSONString(objSource);
            Object clone = JSON.parseObject(tempJson, objSource.getClass());
            return clone;
        }
    
        /**
         * 深度克隆对象
         *
         * @throws IllegalAccessException
         * @throws InstantiationException
         */
        public static Object deepClone(Object objSource) throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
            if (null == objSource) return null;
            //是否jdk类型、基础类型、枚举类型
            if (isJDKType(objSource.getClass())
                    || objSource.getClass().isPrimitive()
                    || objSource instanceof Enum<?>) {
                if ("java.lang.String".equals(objSource.getClass().getName())) {//目前只支持String类型深复制
                    return new String((String) objSource);
                } else {
                    return objSource;
                }
            }
            // 获取源对象类型
            Class<?> clazz = objSource.getClass();
            Object objDes = clazz.newInstance();
            // 获得源对象所有属性
            Field[] fields = getAllFields(objSource);
            // 循环遍历字段,获取字段对应的属性值
            for (Field field : fields) {
                field.setAccessible(true);
                if (null == field) continue;
                Object value = field.get(objSource);
                if (null == value) continue;
                Class<?> type = value.getClass();
                if (isStaticFinal(field)) {
                    continue;
                }
                try {
    
                    //遍历集合属性
                    if (type.isArray()) {//对数组类型的字段进行递归过滤
                        int len = Array.getLength(value);
                        if (len < 1) continue;
                        Class<?> c = value.getClass().getComponentType();
                        Array newArray = (Array) Array.newInstance(c, len);
                        for (int i = 0; i < len; i++) {
                            Object arrayObject = Array.get(value, i);
                            Array.set(newArray, i, deepClone(arrayObject));
                        }
                    } else if (value instanceof Collection<?>) {
                        Collection newCollection = (Collection) value.getClass().newInstance();
                        Collection<?> c = (Collection<?>) value;
                        Iterator<?> it = c.iterator();
                        while (it.hasNext()) {
                            Object collectionObj = it.next();
                            newCollection.add(deepClone(collectionObj));
                        }
                        field.set(objDes, newCollection);
                        continue;
                    } else if (value instanceof Map<?, ?>) {
                        Map newMap = (Map) value.getClass().newInstance();
                        Map<?, ?> m = (Map<?, ?>) value;
                        Set<?> set = m.entrySet();
                        for (Object o : set) {
                            Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
                            Object mapVal = entry.getValue();
                            newMap.put(entry.getKey(), deepClone(mapVal));
                        }
                        field.set(objDes, newMap);
                        continue;
                    }
    
                    //是否jdk类型或基础类型
                    if (isJDKType(field.get(objSource).getClass())
                            || field.getClass().isPrimitive()
                            || isStaticType(field)
                            || value instanceof Enum<?>) {
                        if ("java.lang.String".equals(value.getClass().getName())) {//目前只支持String类型深复制
                            field.set(objDes, new String((String) value));
                        } else {
                            field.set(objDes, field.get(objSource));
                        }
                        continue;
                    }
    
                    //是否枚举
                    if (value.getClass().isEnum()) {
                        field.set(objDes, field.get(objSource));
                        continue;
                    }
    
                    //是否自定义类
                    if (isUserDefinedType(value.getClass())) {
                        field.set(objDes, deepClone(value));
                        continue;
                    }
    
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return objDes;
        }
    
    
        /**
         * 是否静态变量
         *
         * @param field
         * @return
         */
        private static boolean isStaticType(Field field) {
            return field.getModifiers() == 8 ? true : false;
        }
    
        private static boolean isStaticFinal(Field field) {
            return Modifier.isFinal(field.getModifiers()) && Modifier.isStatic(field.getModifiers());
        }
    
        /**
         * 是否jdk类型变量
         *
         * @param clazz
         * @return
         * @throws IllegalAccessException
         */
        private static boolean isJDKType(Class clazz) throws IllegalAccessException {
            //Class clazz = field.get(objSource).getClass();
            return StringUtils.startsWith(clazz.getPackage().getName(), "javax.")
                    || StringUtils.startsWith(clazz.getPackage().getName(), "java.")
                    || StringUtils.startsWith(clazz.getName(), "javax.")
                    || StringUtils.startsWith(clazz.getName(), "java.");
        }
    
        /**
         * 是否用户自定义类型
         *
         * @param clazz
         * @return
         */
        private static boolean isUserDefinedType(Class<?> clazz) {
            return
                    clazz.getPackage() != null
                            && !StringUtils.startsWith(clazz.getPackage().getName(), "javax.")
                            && !StringUtils.startsWith(clazz.getPackage().getName(), "java.")
                            && !StringUtils.startsWith(clazz.getName(), "javax.")
                            && !StringUtils.startsWith(clazz.getName(), "java.");
        }
    
        /**
         * 获取包括父类所有的属性
         *
         * @param objSource
         * @return
         */
        public 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;
        }
    
        /**
         * 深度克隆对象
         *
         * @throws IllegalAccessException
         * @throws InstantiationException
         */
        @Deprecated
        public static Object copy(Object objSource) throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
    
            if (null == objSource) return null;
            // 获取源对象类型
            Class<?> clazz = objSource.getClass();
            Object objDes = clazz.newInstance();
            // 获得源对象所有属性
            Field[] fields = getAllFields(objSource);
            // 循环遍历字段,获取字段对应的属性值
            for (Field field : fields) {
                field.setAccessible(true);
                // 如果该字段是 static + final 修饰
                if (field.getModifiers() >= 24) {
                    continue;
                }
                try {
                    // 设置字段可见,即可用get方法获取属性值。
                    field.set(objDes, field.get(objSource));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return objDes;
        }
    }
    

    敏感信息注解标记类:

    package com.ciip.cloud.core.usercenter.config.aliyun;
    
    import com.ciip.cloud.core.common.constant.enums.usercenter.SensitiveTypeEnum;
    
    import java.lang.annotation.*;
    
    /**
     * Title: Desensitized
     * Description: 敏感信息注解标记
     *
     * @author jintian
     * @created 2019/5/23 11:11
     */
    @Target({ElementType.FIELD, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    @Documented
    public @interface Desensitized {
    
        /*脱敏类型(规则)*/
        SensitiveTypeEnum type();
    
        /*判断注解是否生效的方法*/
        String isEffictiveMethod() default "";
    
    }
    

    脱敏类型(规则):

    package com.ciip.cloud.core.common.constant.enums.usercenter;
    /**
     * Title: SensitiveTypeEnum
     * Description: 脱敏类型(规则)
     *
     * @author jintian
     * @created 2019/5/23 11:15
     */
    public enum  SensitiveTypeEnum {
        /**
         * 中文名
         */
        CHINESE_NAME,
        /**
         * 身份证号
         */
        ID_CARD,
        /**
         * 座机号
         */
        FIXED_PHONE,
        /**
         * 手机号
         */
        MOBILE_PHONE,
        /**
         * 地址
         */
        ADDRESS,
        /**
         * 电子邮件
         */
        EMAIL,
        /**
         * 银行卡
         */
        BANK_CARD,
        /**
         * 密码
         */
        PASSWORD;
    }
    

    实体类通过注解实现脱敏:

    展开全文
  • Java 数据脱敏工具类

    千次阅读 2020-08-19 17:59:36
    数据脱敏工具类 DesensitizationUtils.java import org.apache.commons.lang3.StringUtils; import java.util.Objects; /** * 数据脱敏工具类 * * @Author: Neo * @Date: 2020/8/19 16:21 * @Version: 1.0 *...

    SensitiveInfoUtils.java

    import org.apache.commons.lang3.StringUtils;
    
    import java.util.Objects;
    
    /**
     * 数据脱敏工具类
     *
     * @Author: Neo
     * @Date: 2020/8/19 16:21
     * @Version: 1.0
     */
    public class SensitiveInfoUtils {
    
        /**
         * 默认填充字符
         */
        public static final String DEFAULT_PAD_STR = "*";
    
    
        /**
         * 数据脱敏
         * 当字符创为空串或字符串长度小于等于 2 时,直接返回
         * 当【字符串总长度】减 {@code leftLen} 减 {@code rightLen} 小于等于 【字符串总长度】的三分之一时,则左右各展示【字符串总长度】的三分之一
         *
         * @param data     需要脱敏的数据
         * @param leftLen  左边展示几位
         * @param rightLen 右边展示几位
         * @param padStr   填充字符串,如果长度为 1, 则按位填充;否则否则直接填充,可用于颜文字填充场景
         * @return
         */
        public static String process(String data, Integer leftLen, Integer rightLen, String padStr) {
            int length = StringUtils.length(data);
            if (StringUtils.isBlank(data) || length <= 2) {
                return data;
            }
    
            int oneThird = length / 3;
    
            // 设置默认值
            leftLen = Objects.isNull(leftLen) ? oneThird : leftLen;
            rightLen = Objects.isNull(rightLen) ? oneThird : rightLen;
            padStr = StringUtils.isBlank(padStr) ? DEFAULT_PAD_STR : padStr;
    
            if (length - leftLen - rightLen <= oneThird) {
                leftLen = oneThird;
                rightLen = oneThird;
            }
    
    
            String left = StringUtils.left(data, leftLen);
            String right = StringUtils.right(data, rightLen);
            if (StringUtils.length(padStr) == 1) {
                return StringUtils.rightPad(left, data.length() - rightLen, padStr).concat(right);
            }
            return left + padStr + right;
        }
    
        /**
         * 数据脱敏
         * 
         * @Author: Neo
         * @Date: 2020/8/19 16:59
         * @Version: 1.0
         */
        public static String process(String data, Integer leftLen, Integer rightLen) {
            return process(data, leftLen, rightLen, DEFAULT_PAD_STR);
        }
    
        /**
         * 证件号码脱敏,输出【前六后四】: 422824********8732
         *
         * @Author: Neo
         * @Date: 2020/8/19 16:23
         * @Version: 1.0
         */
        public static String idcard(String idcard) {
            return process(idcard, 6, 4);
        }
    
        public static void main(String[] args) {
            System.out.println(process("110101199003070513", 6, 4));
            System.out.println(process("1234567890", 6, 4));
            System.out.println(process("1234567890", 6, 4, "(*^▽^*)"));
        }
    }
    

    测试结果

    110101********0513
    123****890
    123(*^▽^*)890
    
    展开全文
  • package ... import org.apache.commons.lang3.StringUtils; /** * @author Thinking * @date 2019/12/10 10:23 * @description 数据脱敏工具类 */ public final class DesensitizationUtil { ...
    package cn.xxxxxx.excutor.util;
    
    import org.apache.commons.lang3.StringUtils;
    
    /**
     * @author Thinking
     * @date 2019/12/10 10:23
     * @description 数据脱敏工具类
     */
    public final class DesensitizationUtil {
    
        /**
         * [中文姓名] 只显示第一个汉字,其他隐藏为星号<例子:李**>
         *
         * @param fullName 姓名
         * @return
         */
        public static String chineseName(String fullName) {
            if (StringUtils.isBlank(fullName)) {
                return "";
            }
            String name = StringUtils.left(fullName, 1);
            return StringUtils.rightPad(name, StringUtils.length(fullName), "*");
        }
    
        /**
         * [中文姓名] 只显示姓氏,其他隐藏为星号<例子:欧阳娜娜  : 欧阳**>
         *
         * @param familyName  姓氏
         * @param givenName   名字
         * @return
         */
        public static String chineseName(String familyName, String givenName) {
            if (StringUtils.isBlank(familyName) || StringUtils.isBlank(givenName)) {
                return "";
            }
            if(familyName.length()>1){
                String name = StringUtils.left(familyName, familyName.length());
                return StringUtils.rightPad(name, StringUtils.length(familyName+givenName), "*");
            }
            return chineseName(familyName + givenName);
        }
    
        /**
         * [地址] 只显示到地区,不显示详细地址;我们要对个人信息增强保护<例子:北京市海淀区****>
         *
         * @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, "*");
        }
    
        /**
         * [手机固话] 电话中间隐藏,前面保留3位明文,后面保留4位明文 <例子:176****6506>
         *
         * @param num 电话号码
         * @param index 3
         * @param end 4
         * @return
         */
        public static String mobileEncrypt(String num,int index,int end) {
            if (StringUtils.isBlank(num)) {
                return "";
            }
            return StringUtils.left(num, index).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(num, end), StringUtils.length(num), "*"), "***"));
        }
    
        /**
         * [电子邮箱] 邮箱前缀隐藏,用星号代替,@及后面的地址显示 <例子:******@163.com>
         *
         * @param email
         * @return
         */
        public static String email(String email) {
            if (StringUtils.isBlank(email)) {
                return "";
            }
            int index = StringUtils.indexOf(email, "@");
            if (index <= 1) {
                return email;
            } else{
                //特殊处理: index = 6 表示部分隐藏时默认用6个*表示用户名
                return StringUtils.rightPad(StringUtils.left(email, 0), 6, "*").concat(StringUtils.mid(email, index, StringUtils.length(email)));
            }
        }
    
    
        /**
         * [自定义规则] 卡号开头用星号隐藏几位,每位1个星号 <例子:******789>
         *
         * @param cardNum
         * @param hideDigit 隐藏位数 6
         * @return
         */
        public static String hideLeftNum(String cardNum, int hideDigit) {
            if (StringUtils.isBlank(cardNum)) {
                return "";
            }
            int length = StringUtils.length(cardNum);
            return StringUtils.leftPad(StringUtils.right(cardNum, length - hideDigit), length, "*");
        }
    
        /**
         * [自定义规则] 卡号后面用星号隐藏几位,每位1个星号<例子:6222600******>
         *
         * @param cardNum
         * @param hideDigit 隐藏位数 6
         * @return
         */
        public static String hideRightNum(String cardNum, int hideDigit) {
            if (StringUtils.isBlank(cardNum)) {
                return "";
            }
            int length = StringUtils.length(cardNum);
            return StringUtils.rightPad(StringUtils.left(cardNum, length - hideDigit), length, "*");
        }
    
        /**
         * [自定义规则] 卡号中间用星号隐藏几位,每位1个星号<例子:622******600>
         *
         * @param cardNum
         * @param hideDigit 隐藏位数 6
         * @return
         */
        public static String hideCenterNum(String cardNum, int hideDigit) {
            if (StringUtils.isBlank(cardNum)) {
                return "";
            }
            int length = StringUtils.length(cardNum);
            int index = (length - hideDigit) >> 1;
            if(hideDigit % 2 == 0){
                index += 1;
            }
            return StringUtils.left(cardNum, index).concat(StringUtils.leftPad(StringUtils.right(cardNum, length-index-hideDigit), length-index, "*"));
        }
    
        /**
         * [自定义规则] 卡号用星号隐藏,每位1个星号<例子:*********>
         *
         * @param cardNum
         * @return
         */
        public static String hideAllNum(String cardNum) {
            if (StringUtils.isBlank(cardNum)) {
                return "";
            }
            int length = StringUtils.length(cardNum);
            return StringUtils.leftPad(StringUtils.right(cardNum, 0), length, "*");
        }
    
    }
    

    参考文章:https://www.cnblogs.com/sinosoft/p/10857788.html

    展开全文
  • Java编程:常用的字段脱敏工具类

    千次阅读 2019-12-16 20:13:56
    //护照前2后3位脱敏,护照一般为8或9位 public static String idPassport ( String id ) { if ( StringUtils . isEmpty ( id ) || ( id . length ( ) < 8 ) ) { return id ; } ...
  • 信息脱敏工具类

    2021-01-13 16:11:51
    DesensitizationUtil.java ... * 通用脱敏工具类 * 可用于: * 用户名 * 手机号 * 邮箱 * 地址等 */ public class DesensitizationUtil { private static final int SIZE = 6; private static final String
  • package utils; import com.google.common.base.Charsets; import com.google.common.io.Files; import java.io.File; import java.io.IOException; import java.util.List; import java.util.regex.Matcher...im...
  • * @description 数据脱敏工具类 * @date 2021/4/7 */ public final class SensitiveInfoUtils { /** * [中文姓名] 如果长度为2,后一位隐藏为星号<例子:李*>,如果长度>2,中间隐藏为星号<例子.
  • 手机号码脱敏工具类

    千次阅读 2019-08-13 20:52:49
    * 手机号脱敏筛选正则 */ public static final String PHONE_BLUR_REGEX = "(\\d{3})\\d{4}(\\d{4})"; /** * 手机号脱敏替换正则 */ public static final String PHONE_BLUR_REPLACE_REGEX = "$1****$2"; ...
  • Java字符串脱敏工具类

    千次阅读 2019-05-17 16:42:07
    * ClassName: 敏感字段处理工具类 * Function: TODO ADD FUNCTION. * Reason: TODO ADD REASON(可选). * date: 2018年5月18日 下午16:02:37 * * @author huangSir * @version ...
  • Java 数据脱敏 工具类

    2019-05-13 17:19:00
    * 敏感信息屏蔽工具 */ public final class SensitiveInfoUtils { // private final static Logger logger = Logger.getLogger(SensitiveInfoUtils.class); /** * [中文姓名] 只显示第一个汉字...
  • 身份证脱敏工具类

    千次阅读 2019-08-13 20:53:45
    import org.apache.commons.lang3.StringUtils; public class IdCardUtils { ... //身份证前三后四脱敏 public static String idEncrypt(String id) { if (StringUtils.isEmpty(id) || (id.length() < 11))...
  • 数据脱敏工具类

    2019-08-20 18:51:36
    import org.apache.commons.lang.StringUtils;... * @Description:脱敏工具 */ public class DesensitizedUtils { /** * 【中文姓名】只显示第一个汉字,其他隐藏为2个星号,比如:李** * ...
  • package io.renren.modules.utils; import org.apache.commons.lang3.StringUtils;...* 敏感数据脱敏工具类 */ public class Desensitization { /** * 身份证号脱敏 * * @param idCard *...
  • package com.tms.common.utils; import ... public class EncryptionUtils { /** * 定义所有常量 ... public static final int ONE = 1;... public static final int TWO = 2;... public
  • 针对客户一些敏感信息做脱敏特殊处理,直接上代码吧! package com.dcorepay.cloudpay.web.tenant.web.utils; import com.dcorepay.cloudpay.common.util.Utils; import org.apache.commons.lang3.StringUtils; ...
  • 通用脱敏工具类 public class DesensitizationUtil { private static final int SIZE = 6; private static final String SYMBOL = "*"; /** * 通用脱敏方法 * @param value * @return */ public static ...
  • * @title: 脱敏工具类 * @author: wll * @since: 2021-9-3 9:54:04 */ public class CommonUtils { // 手机号码前三后四脱敏 public static String encryptMobile(String mobile) { if (StringUtils
  • 前言 随着科技和信息化时代的加速发展,尤其在5G和大数据时代的今天,信息安全也逐渐成为人民更为...今天主要讲述后台系统对于敏感数据进行日志脱敏处理,拿来即用的工具实现。利用logback工具包的日志脱敏处理,非
  • 工具类做个记录,直接上代码: 执行效果: 注:以上内容仅提供参考和交流,请勿用于商业用途,如有侵权联系本人删除!

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,707
精华内容 1,482
关键字:

脱敏工具类