实现敏感字段脱敏注解@Sensitive

前言

在B2C项目中,就以电商项目举例,都有前台与后台。并且这类项目的后台往往都会开放给公司内大部分人,甚至有些是将电商项目作为Saas服务提供给外部厂商的,这样后台中记录的用户数据就成为一个风险点,随着越来越多的人可以接触到后台系统,我们必须对用户的数据进行加密不仅限于在数据库层面加密存储,前端展示的时候也必须要对例如:手机号,地址,身份证号等等隐私数据进行脱敏处理。

实现方式

1.最容易想到的就是利用硬编码的形式,哪些接口中涉及到了隐私数据,我们就去接口中对隐私数据进行脱敏。(ps一开始我确实是这么做的)

2.但是我发现太多太多接口都需要使用用户隐私数据了,我人工一个一个手工改也太不优雅了!我就想到我们能不能在SpringMVC将数据写入response的时候就将他拦截住,然后我实现一个注解,其实这个注解也就是一个标识。我们通过反射对于被这个注解标注的字段进行脱敏处理,然后再写回对象中。

这样不就可以只对响应类中加一个注解,然后所有使用用户敏感数据的接口都直接脱敏了吗,而且我们也可以很方便的改变我们的脱敏策略!!!

代码

hutools工具依赖

最适合中国宝宝体质的中国工具包,虽然网上很多人喷他,但是我个人觉得还是挺好用的,可能是我段位还不够。

xml 复制代码
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.11</version>
</dependency>

@Sensitive注解

less 复制代码
/**
 * @projectName: BlossomKnowledge
 * @package: blossom.project.bk.common.annotaion
 * @className: Sensitive
 * @author: Link Ji
 * @description: GOGO
 * @VX: _Aeeee86
 * @date: 2024/9/28 16:36
 * @version: 1.0
 */
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Sensitive {
    SensitiveDataType type() default SensitiveDataType.PASSWORD;

}

脱敏策略枚举类

typescript 复制代码
/**
 * @projectName: BlossomKnowledge
 * @package: blossom.project.bk.common.enums
 * @className: SensitiveDataType
 * @author: Link Ji
 * @description: GOGO
 * @VX: _Aeeee86
 * @date: 2024/9/28 16:40
 * @version: 1.0
 */
public enum SensitiveDataType {
    //脱敏数据类型
    NAME("name"),
    ID_CARD("idCard"),
    PHONE("phone"),
    EMAIL("email"),
    BANK_CARD("bankCard"),
    ADDRESS("address"),
    PASSWORD("password"),
    ;

    SensitiveDataType(String type) {
        this.type = type;
    }
    @Getter
    private String type;
}

响应拦截器

这里就是最核心的代码了,利用了SpringMVC提供的钩子接口,ResponseBodyAdvice接口,其中提供了一个beforeBodyWrite方法,这个方法就可以在数据写入响应前可以对数据进行处理。

typescript 复制代码
/**
 * @projectName: BlossomKnowledge
 * @package: blossom.project.bk.common.enums
 * @className: SensitiveDataType
 * @author: Link Ji
 * @description: GOGO
 * @VX: _Aeeee86
 * @date: 2024/9/28 16:40
 * @version: 1.0
 */
@ControllerAdvice
public class SensitiveDataAdvice implements ResponseBodyAdvice<Object> {

    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        // 拦截所有响应
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, org.springframework.http.MediaType selectedContentType,
                                  Class<? extends HttpMessageConverter<?>> selectedConverterType,
                                  org.springframework.http.server.ServerHttpRequest request,
                                  org.springframework.http.server.ServerHttpResponse response) {
        // 如果返回类型是result
        if (body instanceof Result<?>){
            // 处理对象,进行脱敏操作
            handleSensitiveFields((Result<?>) body);
        }

        return body;
    }

    private void handleSensitiveFields(Result<?> res) {
        Object data = res.getData();
        //获取data的下的全部字段
        if (data == null) {
            return;
        }
        Field[] fields = data.getClass().getDeclaredFields();
        for (Field field : fields) {
            // 判断是否有 @SensitiveData 注解
            if (field.isAnnotationPresent(Sensitive.class)) {
                Sensitive annotation = field.getAnnotation(Sensitive.class);
                SensitiveDataType sensitiveDataType = annotation.type();
                field.setAccessible(true);
                try {
                    Object value = field.get(data);
                    if (value instanceof String) {
                        // 执行脱敏操作
                        String maskedValue = DesensitizationUtils.maskData((String) value, sensitiveDataType.getType());
                        field.set(data, maskedValue);
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

脱敏工具类

这个工具类依赖于hutools提供的DesensitizedUtil

typescript 复制代码
public class DesensitizationUtils {
    
    public static String maskData(String data, String type) {
        if (data == null) {
            return null;
        }
        //使用switch匹配SensitiveDataType枚举中的类型,并且使用hutool脱敏工具类进行脱敏
       return switch (type) {
           case "name" -> DesensitizedUtil.chineseName(data);
           case "idCard" -> DesensitizedUtil.idCardNum(data, 2, data.length() - 2);
           case "phone" -> DesensitizedUtil.mobilePhone(data);
           case "email" -> DesensitizedUtil.email(data);
           case "bankCard"-> DesensitizedUtil.bankCard(data);
           case "address" -> DesensitizedUtil.address(data, data.length() - 6);
           default -> data;
       };

    }
}

效果演示

相关推荐
媛媛要加油呀22 分钟前
鸿蒙面试题库收集(一):ArkTS&ArkUI-基础理论
华为·面试·职场和发展·harmonyos
Red Red32 分钟前
秋招|面试|群面|求职
笔记·学习·面试·职场和发展
誓则盟约33 分钟前
基于Spring框架的分层解耦详解
java·后端·spring
每天的积累1 小时前
面试知识点总结篇四
面试
customer081 小时前
【开源免费】基于SpringBoot+Vue.JS墙绘产品展示交易平台(JAVA毕业设计)
java·jvm·vue.js·spring boot·后端·spring cloud·开源
paopaokaka_luck2 小时前
基于Spring Boot+Vue前后端分离的中医药科普系统设计和实现(协同过滤算法)【原创】
java·vue.js·spring boot·后端·毕业设计
影子落人间2 小时前
微服务面试-修改nacos配置,不重启服务怎生效
java·微服务·面试
芝士加2 小时前
面试官:如何直接在浏览器环境编译ES6+/TS代码?
前端·javascript·面试
WHabcwu2 小时前
Spring Web MVC⼊⻔
java·后端·spring·mvc
customer082 小时前
【开源免费】基于SpringBoot+Vue.JS服装销售平台(JAVA毕业设计)
java·vue.js·spring boot·后端·spring cloud·开源·intellij-idea