• 基于注解形式的数据脱敏


    数据脱敏

    注解定义

    package cn.com.sensitive.annotations;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * 敏感方法
     *
     * @author zhanghao
     * @date 2019/06/04
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD})
    public @interface Sensitive {
    }
    package cn.com.sensitive.annotations;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * 数据脱敏
     * 证件类型标识
     *
     * @author zhanghao
     * @date 2019/06/04
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.FIELD})
    public @interface SensitiveCardType {
    
        String idCardType() default "111";
    
        String refField() default "";
    }
    package cn.com.sensitive.annotations;
    
    import cn.com.sensitive.enums.SensitiveType;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * 数据脱敏
     * 敏感字段
     *
     * @author zhanghao
     * @date 2019/06/04
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.FIELD})
    public @interface SensitiveField {
    
        SensitiveType value();
    
        SensitiveCardType cardRef() default @SensitiveCardType();
    }

    枚举类定义

    package cn.com.sensitive.enums;
    
    /**
     * 敏感数据类型
     *
     * @author zhanghao
     * @date 2019/06/04
     */
    public enum SensitiveType {
        /**
         * 姓名
         */
        NAME,
        /**
         * 手机
         */
        MOBILE,
        /**
         * 邮箱
         */
        EMAIL,
        /**
         * 身份证
         */
        IDCARD,
        /**
         * 生日
         */
        BIRTHDAY,
        /**
         * 密码
         */
        PASSWORD,
        /**
         * 银行卡
         */
        BANKCARD,
        /**
         * 薪水
         */
        SALARY,
        /**
         * 其他证件号码
         */
        OTHERCARD,
        /**
         * 不确定哪种证件类型,指向某个字段确定类型
         */
        CARD_REF,
        /**
         * 对象(将对标记为OBJECT的对象会处理该对象里面的字段)
         */
        OBJECT
    
    
    }

    脱敏工具类定义

    package cn.com.sensitive.utils;
    
    import cn.com.sensitive.SensitiveHandler;
    import org.apache.commons.lang3.StringUtils;
    
    import java.util.List;
    
    /**
     * 数据隐私显示 手机号,身份证号和银行卡号等
     */
    public class SensitiveUtils {
    
        /**
         * 手机号
         * 手机号留前4位和后4位,其他*
         *
         * @param phone
         * @return
         */
        public static String maskMobile(String phone) {
            if(StringUtils.isBlank(phone)) {
                return "";
            }
            if(StringUtils.length(phone)<8) {
                return phone;
            }
            int start = 4;
            int end = phone.length() - 4;
            StringBuffer overPlay = new StringBuffer();
            for (int i = start; i < end; i++) {
                overPlay.append("*");
            }
            return StringUtils.overlay(phone, overPlay.toString(), start, end);
        }
    
        /**
         * 邮箱账号
         * 邮箱留前4位及@符号以后,其他*
         *
         * @param email
         * @return
         */
        public static String maskEmail(String email) {
            if (StringUtils.isEmpty(email)) {
                return "";
            }
            String at = "@";
            if (!email.contains(at)) {
                return email;
            }
            /**
             * 这里主要逻辑是需要保留邮箱的注册商 比如@qq.com
             * 后四位打码,不足四位,除了@前都打码
             */
            int index = StringUtils.indexOf(email, at);
            String content = StringUtils.substring(email, 0, index);
            String mask = "";
            if (content.length() > 4) {
                int start = 4;
                int end = index;
                StringBuffer overPlay = new StringBuffer();
                for (int i = start; i < end; i++) {
                    overPlay.append("*");
                }
                mask = StringUtils.overlay(content, overPlay.toString(), 4, content.length());
            } else {
                int start = 0;
                int end = index;
                StringBuffer overPlay = new StringBuffer();
                for (int i = start; i < end; i++) {
                    overPlay.append("*");
                }
                mask = overPlay.toString();
            }
            return mask + StringUtils.substring(email, index);
        }
    
        /**
         * 身份证打码操作
         * 身份证留前4位和后3位,其他 *
         *
         * @param idCard
         * @return
         */
        public static String maskIdCard(String idCard) {
            if(StringUtils.isBlank(idCard)) {
                return "";
            }
            if(StringUtils.length(idCard)<7) {
                return idCard;
            }
            int start = 4;
            int end = idCard.length() - 3;
            StringBuffer overPlay = new StringBuffer();
            for (int i = start; i < end; i++) {
                overPlay.append("*");
            }
            return StringUtils.overlay(idCard, overPlay.toString(), start, end);
        }
    
        /**
         * 生日打码操作
         * 中间月日打码。生日年月日
         *
         * @param birthday
         * @return
         */
        public static String maskBirthday(String birthday) {
            if(StringUtils.isBlank(birthday)) {
                return "";
            }
            if(StringUtils.length(birthday)<=4) {
                return birthday;
            }
            String pre = birthday.substring(0, 4);
            String suf = birthday.substring(4);
            String sufResult = StringUtils.replaceAll(suf, "[0-9]", "*");
            return pre + sufResult;
        }
    
        /**
         * 银行卡号
         * 银行账号留前4位和后4位,其他*
         *
         * @param bandCard
         * @return
         */
        public static String maskBankCard(String bandCard) {
            if(StringUtils.isBlank(bandCard)) {
                return "";
            }
            if(StringUtils.length(bandCard)<8) {
                return bandCard;
            }
            int start = 4;
            int end = bandCard.length() - 4;
            StringBuffer overPlay = new StringBuffer();
            for (int i = start; i < end; i++) {
                overPlay.append("*");
            }
            return StringUtils.overlay(bandCard, overPlay.toString(), start, end);
        }
    
        /**
         * 密码全部打码
         *
         * @param password
         * @return
         */
        public static String maskPassword(String password) {
            if(StringUtils.isBlank(password)) {
                return "";
            }
            int end = password.length();
            StringBuffer overPlay = new StringBuffer();
            for (int i = 0; i < end; i++) {
                overPlay.append("*");
            }
            return StringUtils.overlay(password, overPlay.toString(), 0, end);
        }
    
        /**
         * 中文姓名,除了第一位不打码
         *
         * @param name
         * @return
         */
        public static String maskName(String name) {
            if(StringUtils.isBlank(name)) {
                return "";
            }
            int end = name.length();
            StringBuffer overPlay = new StringBuffer();
            for (int i = 1; i < end; i++) {
                overPlay.append("*");
            }
            return StringUtils.overlay(name, overPlay.toString(), 1, end);
        }
    
        /**
         * 月薪,全部*
         *
         * @param salary
         * @return
         */
        public static String maskSalary(String salary) {
            if(StringUtils.isBlank(salary)) {
                return "";
            }
            int end = salary.length();
            StringBuffer overPlay = new StringBuffer();
            for (int i = 0; i < end; i++) {
                overPlay.append("*");
            }
            return StringUtils.overlay(salary, overPlay.toString(), 0, end);
        }
    
        /**
         * 其他证件号码前1位和后3位其他全部为*
         *
         * @param otherCard
         * @return
         */
        public static String maskOtherCard(String otherCard) {
            if(StringUtils.isBlank(otherCard)) {
                return "";
            }
            if(StringUtils.length(otherCard)<4) {
                return otherCard;
            }
            int start = 1;
            int end = otherCard.length() - 3;
            StringBuffer overPlay = new StringBuffer();
            for (int i = start; i < end; i++) {
                overPlay.append("*");
            }
            return StringUtils.overlay(otherCard, overPlay.toString(), start, end);
        }
    
    
        /**
         * 对list结果集支持
         * @param list
         * @param <T>
         * @throws Exception
         */
        public static <T> void supportList(List<T> list){
            for (T t : list) {
                try {
                    SensitiveHandler.handle(t);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
        /**
         * 对object结果集支持
         * @param t
         * @param <T>
         * @throws Exception
         */
        public static <T> void supportObject(T t){
            try {
                SensitiveHandler.handle(t);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    }

    核心处理器

    package cn.com.sensitive;
    
    import cn.com.sensitive.annotations.SensitiveCardType;
    import cn.com.sensitive.annotations.SensitiveField;
    import cn.com.sensitive.enums.SensitiveType;
    import cn.com.sensitive.utils.SensitiveUtils;
    import org.apache.commons.collections4.CollectionUtils;
    import org.apache.commons.lang3.StringUtils;
    import org.apache.commons.lang3.reflect.FieldUtils;
    
    import java.lang.reflect.Field;
    import java.util.List;
    import java.util.Objects;
    
    public class SensitiveHandler {
    
        public static void handle(Object obj) throws Exception {
            if (null != obj) {
                Class<?> objClazz = obj.getClass();
                if (null != objClazz) {
                    List<Field> allFieldsList = FieldUtils.getAllFieldsList(objClazz);
                    if (CollectionUtils.isNotEmpty(allFieldsList)) {
                        for (Field declaredField : allFieldsList) {
                            declaredField.setAccessible(true);
                            SensitiveField sensitiveField = declaredField.getAnnotation(SensitiveField.class);
                            if (null != sensitiveField) {
                                Object fieldVal = declaredField.get(obj);
                                if (null != fieldVal) {
                                    if (SensitiveType.OBJECT.equals(sensitiveField.value())) {
                                        handle(fieldVal);
                                    } else if(SensitiveType.CARD_REF.equals(sensitiveField.value())) {
                                        // 处理
                                        try {
                                            SensitiveCardType sensitiveCardType = sensitiveField.cardRef();
                                            if(Objects.nonNull(sensitiveCardType)) {
                                                String idCardType = sensitiveCardType.idCardType();
                                                String refField = sensitiveCardType.refField();
                                                if(StringUtils.isNoneBlank(idCardType,refField)) {
                                                    for (Field declaredFieldCur : allFieldsList) {
                                                        declaredFieldCur.setAccessible(Boolean.TRUE);
                                                        if(declaredFieldCur.getName().equals(refField)) {
                                                            Object idCardTypeVal = declaredFieldCur.get(obj);
                                                            String valStr = (String) fieldVal;
                                                            if(String.valueOf(idCardTypeVal).equals(idCardType)) {
                                                                String result = handleSensitiveString(SensitiveType.IDCARD, valStr);
                                                                declaredField.set(obj, result);
                                                            } else {
                                                                String result = handleSensitiveString(SensitiveType.OTHERCARD, valStr);
                                                                declaredField.set(obj, result);
                                                            }
                                                            break;
                                                        }
                                                    }
                                                }
                                            }
                                        } catch (Exception e) {
                                            e.printStackTrace();
                                        }
                                    } else {
                                        // 处理
                                        try {
                                            String valStr = (String) fieldVal;
                                            String result = handleSensitiveString(sensitiveField.value(), valStr);
                                            declaredField.set(obj, result);
                                        } catch (Exception e) {
                                            e.printStackTrace();
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    
        public static String handleSensitiveString(SensitiveType type, String val) {
            try {
                String result = "";
                switch (type) {
                    case NAME:
                        result = SensitiveUtils.maskName(val);
                        break;
                    case MOBILE:
                        result = SensitiveUtils.maskMobile(val);
                        break;
                    case EMAIL:
                        result = SensitiveUtils.maskEmail(val);
                        break;
                    case IDCARD:
                        result = SensitiveUtils.maskIdCard(val);
                        break;
                    case BIRTHDAY:
                        result = SensitiveUtils.maskBirthday(val);
                        break;
                    case PASSWORD:
                        result = SensitiveUtils.maskPassword(val);
                        break;
                    case BANKCARD:
                        result = SensitiveUtils.maskBankCard(val);
                        break;
                    case SALARY:
                        result = SensitiveUtils.maskSalary(val);
                        break;
                    case OTHERCARD:
                        result = SensitiveUtils.maskOtherCard(val);
                        break;
                    default:
                        result = val;
                        break;
                }
                return result;
            } catch (Exception e) {
                e.printStackTrace();
                return val;
            }
        }
    
    }

    WEB支持类

    package cn.com.sensitive;
    
    import lombok.extern.slf4j.Slf4j;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    
    @Aspect
    @Order(9)
    @Component
    @Slf4j
    public class SensitiveAspect {
    
        @Pointcut("@annotation(cn.com.sensitive.annotations.Sensitive)")
        public void pointcut() {
        }
    
        @Around("pointcut()")
        public Object sensitiveAround(ProceedingJoinPoint pjp) throws Throwable {
            Object returnValue = pjp.proceed();
            returnValue = SensitiveAspectSupport.sensitive(pjp, returnValue);
            return returnValue;
        }
    
    }
    package cn.com.sensitive;
    
    import cn.com.LogUtils;
    import cn.com.sensitive.annotations.Sensitive;
    import lombok.extern.slf4j.Slf4j;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.Signature;
    import org.aspectj.lang.reflect.MethodSignature;
    
    import java.lang.reflect.Method;
    import java.util.Arrays;
    
    @Slf4j
    public class SensitiveAspectSupport {
    
    
        public static Object sensitive(JoinPoint pointer, Object returnValue) {
    
            Long methodStartTime = System.currentTimeMillis();
            Signature signature = pointer.getSignature();
            String methodDesc = signature.getDeclaringTypeName() + "." + signature.getName();
            String msgDesc = "数据脱敏";
            LogUtils.info(log,
                    methodDesc,
                    msgDesc,
                    "arguments:{0} ",
                    Arrays.toString(pointer.getArgs()));
    
            try {
                MethodSignature sign = (MethodSignature) signature;
                Method method = sign.getMethod();
                //获取方法上的注解
                Sensitive sensitive = method.getAnnotation(Sensitive.class);
                if(null != sensitive) {
                    SensitiveHandler.handle(returnValue);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            Long methodEndTime = System.currentTimeMillis();
            LogUtils.info(log,
                    methodDesc,
                    msgDesc,
                    " 响应信息:{0}, 方法耗时:{1} 秒", "", (methodEndTime - methodStartTime) / 1000F);
            return returnValue;
    
        }
    
    
    }
  • 相关阅读:
    MySQLday04(剩余窗口函数,其他常用函数,存储引擎,如何选择数据类型,字符集,索引,存储过程,触发器,LOCK TABLES 和 UNLOCK TABLES,事务控制,分布式事务的使用,JDBC)
    MySQLday03(JSON类型,算术运算符,比较运算符,逻辑运算符,位运算符,运算符的优先级,字符串函数,数值函数,日期和时间函数,流程函数,JSON函数,窗口函数)
    Mysqlday02(导入外部sql文件,order by,group by,having,多表联查,查元数据,数值类型,日期类型,字符数据类型)
    Mysqlday01(Mysql简介,sql简介,分类)
    Spring Boot 入门实战(6)--JdbcTempalte、Mybatis 、多数据源及 Atomicos 整合(XA 事务)
    Spring Boot 入门实战(5)--JdbcTempalte、Mybatis及多数据源整合(单库事务)
    Java 操作 XML(11)--XMLBeans 使用
    Qt QThread 创建多线程程序
    C++Primer第五版 第十三章 拷贝控制
    QtCreator float与QString之间的转化
  • 原文地址:https://www.cnblogs.com/bevis-byf/p/12576407.html
Copyright © 2020-2023  润新知