脱敏工具?整个全局的吧

咱又手痒造轮子啦!Hutool工具包有这个一个类DesensitizedUtil实现了一些常见业务数据类型的脱敏,像手机号,中文名,身份证号,银行卡号等。那咱就基于它写一个全局切面,需要脱敏的用注解标识,思路有了说干就干。

咱先定义一个切入点注解@DataDesensitized

java 复制代码
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataDesensitized {
}

然后咱再定义一个注解标识字段脱敏@Desensitized

java 复制代码
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Desensitized {
    //加上hutool类中的脱敏类型枚举选择脱敏策略
    DesensitizedUtil.DesensitizedType type();
}

最后写切面类

java 复制代码
@Aspect
@Component
@Slf4j
public class DataDesensitizedAspect {
    @AfterReturning(pointcut = "@annotation(dd)", returning = "result")
    public void doAfterReturning(JoinPoint joinPoint, DataDesensitized dd, Object result) {
        //TODO 这里可以根据组织架构角色控制是否脱敏
        boolean need = true;
        if (!need) {
            return;
        }
        //方法响应一般有分页实体,list集合,单实体对象,那就分类处理
        if (result instanceof PageInfo) {
            PageInfo page = (PageInfo) result;
            List records = page.getList();
            for (Object record : records) {
                objReplace(record);
            }
        } else if (result instanceof List) {
            List list = (List) result;
            for (Object obj : list) {
                objReplace(obj);
            }
        } else {
            objReplace(result);
        }
    }
    
    public static <T> void objReplace(T t) {
        try {
            Field[] declaredFields = ReflectUtil.getFields(t.getClass());
            for (Field field : declaredFields) {
                Desensitized des = field.getAnnotation(Desensitized.class);
                //被脱敏注解修饰且string类型
                if (des != null &&
                        "class java.lang.String".equals(field.getGenericType().toString())) {
                    Object fieldValue = ReflectUtil.getFieldValue(t, field);
                    if (fieldValue == null || StringUtils.isEmpty(fieldValue.toString())) {
                        continue;
                    }
                    DesensitizedUtil.DesensitizedType type = des.type();
                    String hide = DesensitizedUtil.desensitized(fieldValue.toString(),type);
                    ReflectUtil.setFieldValue(t, field, hide);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

在业务方法上标识切入点注解

java 复制代码
@Override
@DataProtection
public PageInfo<OrderDetailsVo> queryOrderDetails(QueryParam param) {
    return mapper.queryOrderDetails(param);
}

vo实体中需要脱敏的字段加@Desensitized

java 复制代码
@Data
public class OrderDetailsVo {
    private String orderNo;
    private String sn;

    @Desensitized(type = DesensitizedUtil.DesensitizedType.CHINESE_NAME)
    private String username;
    
    @Desensitized(type = DesensitizedUtil.DesensitizedType.MOBILE_PHONE)
    private String mobile;
    
    @Desensitized(type = DesensitizedUtil.DesensitizedType.ID_CARD)
    private String idCard;
}

完成!

次日,产品经理要求这个20位的sn字符串从第五位脱敏到第十八位,hutool工具没有这个类型的枚举!成!咱再把轮子改造一下

自己写一个脱敏策略枚举DesensitizedType,对比hutool只加了CUSTOM自定义脱敏类型

java 复制代码
public enum DesensitizedType {
    //自定义脱敏标识
    CUSTOM,
    //用户id
    USER_ID,
    //中文名
    CHINESE_NAME,
    //身份证号
    ID_CARD,
    //座机号
    FIXED_PHONE,
    //手机号
    MOBILE_PHONE,
    //地址
    ADDRESS,
    //电子邮件
    EMAIL,
    //密码
    PASSWORD,
    //中国大陆车牌,包含普通车辆、新能源车辆
    CAR_LICENSE,
    //银行卡
    BANK_CARD
}

@Desensitized改造

java 复制代码
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Desensitized {
    //替换成自己定义的枚举
    DesensitizedType type() default DesensitizedType.CUSTOM;

    /**
     * 当type不指定时,可自定义脱敏起始位置(包含)
     */
    int startInclude() default 0;

    /**
     * 当type不指定时,可自定义脱敏结束位置(不包含) ,-1代表字符串长度
     */
    int endExclude() default -1;
}

切面类改造

java 复制代码
public static <T> void objReplace(T t) {
    try {
        Field[] declaredFields = ReflectUtil.getFields(t.getClass());
        for (Field field : declaredFields) {
            Desensitized des = field.getAnnotation(Desensitized.class);
            //被脱敏注解修饰且string类型
            if (des != null &&
                    "class java.lang.String".equals(field.getGenericType().toString())) {
                Object fieldValue = ReflectUtil.getFieldValue(t, field);
                if (fieldValue == null || StringUtils.isEmpty(fieldValue.toString())) {
                    continue;
                }
                String value = fieldValue.toString();
                String hide = "";
                if (des.type() == DesensitizedType.CUSTOM) {
                    int startInclude = des.startInclude();
                    int endExclude = des.endExclude();
                    if (endExclude == -1) {
                        endExclude = value.length();
                    }
                    hide = StrUtil.hide(value, startInclude, endExclude);
                } else {
                    DesensitizedUtil.DesensitizedType type = 
                            DesensitizedUtil.DesensitizedType.valueOf(des.type().toString());
                    hide = DesensitizedUtil.desensitized(value, type);
                }
                ReflectUtil.setFieldValue(t, field, hide);
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

实体标识脱敏字段

java 复制代码
@Data
public class OrderDetailsVo {
    private String orderNo;
    
    @Desensitized(startInclude = 5,endExclude = 18)
    private String sn;

    @Desensitized(type = DesensitizedType.CHINESE_NAME)
    private String username;
    
    @Desensitized(type = DesensitizedType.MOBILE_PHONE)
    private String mobile;
    
    @Desensitized(type = DesensitizedType.ID_CARD)
    private String idCard;
}

这下可以开开心心把轮子给小伙伴用啦开心😘😘😘

相关推荐
liuyang-neu1 分钟前
力扣 16.最接近的三数之和
java·数据结构·算法·leetcode
艾伦~耶格尔3 分钟前
Java API 之集合框架进阶
java·开发语言·学习
韩子谦4 分钟前
Java迭代器Iterator和Iterable有什么区别?
java·windows·python
Satan7125 分钟前
【Java】全面理解Java8特性
java·开发语言
至简行远7 分钟前
路由器接口配置DHCP实验简述
java·服务器·网络·数据结构·python·算法·智能路由器
c1tenj28 分钟前
SpringCloud Feign 以及 一个标准的微服务的制作
java·spring cloud·微服务
小郝同学(恩师白云)22 分钟前
SpringMVC后续4
java·服务器·前端
March€27 分钟前
基于mockito做单元测试
java·单元测试·log4j
秋月的私语34 分钟前
c# 线程等待变量的值符合条件
java·jvm·c#
Stringzhua34 分钟前
SpringBean的生命周期
java·spring