基于注解形式的数据脱敏

数据脱敏

注解定义

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;

    }

}

原文地址:https://www.cnblogs.com/bevis-byf/p/12576407.html

时间: 2024-10-09 11:40:02

基于注解形式的数据脱敏的相关文章

SpringMVC + ehcache( ehcache-spring-annotations)基于注解的服务器端数据缓存

背景 声明,如果你不关心java缓存解决方案的全貌,只是急着解决问题,请略过背景部分. 在互联网应用中,由于并发量比传统的企业级应用会高出很多,所以处理大并发的问题就显得尤为重要.在硬件资源一定的情况下,在软件层面上解决高并发问题会比较经济实惠一些.解决并发的根本在于提高系统的响应时间与单位时间的吞吐量.解决问题的思路可分两个维度,一是提高系统的单位时间内的运算效率(比如集群),二是减少系统不必要的开支(比如缓存).缓存又会分为客户端缓存与服务器端缓存,本文就javaEE项目的服务器端缓存方案展

基于注解的形式配置Bean

基于注解的方式配置Bean:也就说我们在每个Bean的类名前面注解一下,Spring会自动帮我们扫描Bean放进IOC容器中 I基于注解的方式配置Bean(没有依赖关系的Bean)有两个步骤: 1组件扫描(component scanning): Spring 能够从 classpath( 类路径下,也就是Src文件夹下)下自动扫描, 侦测和实例化具有特定注解的组件.  特定组件包括: @Component: 基本注解, 标识了一个受 Spring 管理的组件   @Respository: 建

Java 数据脱敏

数据脱敏 数据脱敏又称数据去隐私化或数据变形,是在给定的规则.策略下对敏感数据进行变换.修改的技术机制,能够在很大程度上解决敏感数据在非可信环境中使用的问题.根据数据保护规范和脱敏策略.对业务数据中的敏感信息实施自动变形.实现对敏感信息的隐藏. 脱敏方法 项目是在controller层进行脱敏,查阅google和github有两种较为方便的方法 一种是基于注解 desensitized基于注解的形式进行脱敏 GitHub 一种是基于框架本质上还是注解,但是已经封装好了,当然还提供fastjson

Spring学习笔记-springMVC基于注解的控制器(Demo)

springmvc的整体运行流程图: 基于@Controller和@RequestMapping是springmvc示例代码 在web.xml中配置springmvc核心分发器DispatcherServlet .... <servlet> <servlet-name>springmvc</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </

Spring MVC中基于注解的 Controller

终于来到了基于注解的 Spring MVC 了.之前我们所讲到的 handler,需要根据 url 并通过 HandlerMapping 来映射出相应的 handler 并调用相应的方法以响应请求.实际上,ControllerClassNameHandlerMapping, MultiActionController 和选择恰当的 methodNameResolver(如 InternalPathMethodNameResolver) 就已经可以在很大程度上帮助我们省去不少的 XML 配置,谁让

SSM框架中以注解形式实现事务管理

上一篇博文<SSM三大框架整合详细教程>详细说了如何整合Spring.SpringMVC和MyBatis这三大框架.但是没有说到如何配置mybatis的事务管理,实现开发中,事务是必不可少的.本篇作为对上一篇的补充,说明在SSM框架中如何使用注解的形式进行事务管理. 什么是事务? 在编写业务的过程中,会需要进行事务处理,当需要执行多条插入语句时,如果前几条成功,而最后一条失败,那么我们需要回滚数据库操作,保持数据的一致性和完整性,此时,就需要利用DB的事务处理.事务是恢复和并发控制的基本单位.

SSM框架——以注解形式实现事务管理

上一篇博文<SSM三大框架整合详细教程>详细说了如何整合Spring.SpringMVC和MyBatis这三大框架.但是没有说到如何配置mybatis的事务管理,在编写业务的过程中,会需要进行事务处理,当需要执行多条插入语句时,如果前几条成功,而最后一条失败,那么我们需要回滚数据库操作,保持数据的一致性和完整性,此时,就需要利用DB的事务处理.事务是恢复和并发控制的基本单位. 简单来说,所谓的事务,是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位. 事务应该具有4个

学习笔记_springmvc注解形式的开发参数接收

springmvc基于注解的开发 注解第一个例子 1. 创建web项目 springmvc-2 2. 在springmvc的配置文件中指定注解驱动,配置扫描器 <!-- sprimgmvc 注解驱动 --> <!-- <mvc:annotation-driven /> --> <!-- springmvc的扫描器,一旦有扫描器的定义上面的mvc:annotation.. 就不需要了,扫描器已经有哪里注解驱动的功能 --> <context:compon

Spring的历史论(数据脱敏)

目前很多公司的架构,从Struts2迁移到了SpringMVC.你有想过为什么不使用Servlet+JSP来构建Java web项目,而是采用SpringMVC呢? 既然这样,我们从源头说起.Struts2的源头其实也是Servlet.Servlet的作用是接收浏览器传给服务端的请求(request),并将服务端处理完的响应(response)返回给用户的浏览器,浏览器和服务端之间通过http协议进行沟通,其过程是浏览器根据用户的选择将相关信息按http协议报文的规范组装请求的http报文,报文