浅析如何在SpringBoot中实现数据脱敏

 更新时间:2024年03月14日 08:40:31   作者:一只爱撸猫的程序猿  
脱敏是指在不改变原数据结构的前提下,通过某种方式处理数据,使数据不能直接暴露用户的真实信息,下面我们就来看看SpringBoot中实现数据脱敏的具体方法吧

在Spring Boot项目中实现字段的脱敏通常涉及到敏感信息的处理,如用户的姓名、电话号码、电子邮件地址等。脱敏是指在不改变原数据结构的前提下,通过某种方式处理数据,使数据不能直接暴露用户的真实信息。

通过Jackson序列化机制实现的关键点

1. 自定义注解 SensitiveInfo

自定义注解SensitiveInfo是一个标记,它让我们能够在字段上指定该字段需要进行脱敏处理,并定义脱敏类型。当Jackson序列化对象时,并不会直接处理这个注解,而是等待序列化器去识别并根据这个注解的属性来执行相应的逻辑。

2. 自定义序列化器 SensitiveInfoSerialize

SensitiveInfoSerialize继承自JsonSerializer,并实现了ContextualSerializer接口。这个序列化器是脱敏逻辑的核心,其主要方法说明如下:

  • serialize:这是覆盖自JsonSerializer的方法,定义了具体的序列化逻辑。当字段被序列化时,这个方法会被调用,并根据脱敏类型进行相应的处理。
  • createContextual:这是ContextualSerializer接口的方法。Jackson调用此方法来创建一个上下文感知的序列化器实例。此方法检查被注解的字段,提取注解SensitiveInfo的类型,并用这个信息创建一个新的序列化器实例。

3. 序列化过程

当Jackson执行序列化过程时,对于每个字段,它将检查字段是否有自定义的序列化器。如果有(在下边的例子中,是@JsonSerialize指定的SensitiveInfoSerialize),Jackson会使用这个序列化器来处理字段。

在序列化器中,createContextual方法会根据字段的SensitiveInfo注解确定需要使用的脱敏类型。这样,每个字段都可以有其专属的脱敏逻辑。

当到达serialize方法时,序列化器已经知道该如何处理字段(例如,是将电话号码中间四位替换成星号,还是将邮箱的用户名部分脱敏)。然后,它执行相应的脱敏操作并输出结果。

4. 动态性

这种设计的一个关键优势是其动态性。通过注解和自定义序列化器,我们可以在不同的字段上应用不同的脱敏规则,甚至可以在运行时改变脱敏行为。所有这些都不需要更改实体类本身的代码,只需要修改注解或者序列化器的逻辑即可。

5. 解耦

这种方法还有助于将业务逻辑(如何脱敏)与数据结构(用户实体)解耦。你可以在不影响实体类的情况下,通过修改序列化器来改变脱敏逻辑,使得代码更加模块化,易于维护和测试。

通过Jackson序列化机制实现的实例代码

步骤 1:定义脱敏注解

首先,定义一个脱敏注解SensitiveInfo,用来标注需要脱敏的字段。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SensitiveInfo {
    SensitiveType type();
}

enum SensitiveType {
    PHONE_NUMBER,
    EMAIL
}

步骤 2:创建自定义序列化器

然后,创建一个自定义的序列化器SensitiveInfoSerialize来处理标注了SensitiveInfo注解的字段。

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;

import java.io.IOException;

public class SensitiveInfoSerialize extends JsonSerializer<String> implements ContextualSerializer {

    private SensitiveType type;

    public SensitiveInfoSerialize() {}

    public SensitiveInfoSerialize(SensitiveType type) {
        this.type = type;
    }

    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        switch (type) {
            case PHONE_NUMBER:
                gen.writeString(DesensitizationUtil.desensitizePhoneNumber(value));
                break;
            case EMAIL:
                gen.writeString(DesensitizationUtil.desensitizeEmail(value));
                break;
            default:
                gen.writeString(value);
        }
    }

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) {
        Annotated annotated = property.getMember();
        SensitiveInfo sensitiveInfo = annotated.getAnnotation(SensitiveInfo.class);
        if (sensitiveInfo != null) {
            return new SensitiveInfoSerialize(sensitiveInfo.type());
        }
        return this;
    }
}

步骤 3:应用注解到实体类

在实体类User中,使用@JsonSerialize注解结合SensitiveInfo来指定哪些字段需要脱敏。

public class User {
    private String name;

    @JsonSerialize(using = SensitiveInfoSerialize.class)
    @SensitiveInfo(type = SensitiveType.PHONE_NUMBER)
    private String phoneNumber;

    @JsonSerialize(using = SensitiveInfoSerialize.class)
    @SensitiveInfo(type = SensitiveType.EMAIL)
    private String email;

    // 省略构造方法、getter和setter
}

步骤 4:序列化并验证结果

现在,当我们序列化User对象时,指定的字段将自动进行脱敏处理。

public class Main {
    public static void main(String[] args) throws JsonProcessingException {
        User user = new User("Alice", "1234567890", "alice@example.com");
        ObjectMapper mapper = new ObjectMapper();
        String result = mapper.writeValueAsString(user);
        System.out.println(result);
    }
}

当运行上述代码时,你将看到控制台输出脱敏后的用户信息,其中电话号码和邮箱字段已根据我们的脱敏逻辑进行了处理。

这种方法的优点是脱敏逻辑与业务逻辑解耦,通过注解即可灵活地对任何字段进行脱敏,不需要修改实体类或者在每次序列化时手动调用脱敏方法。这样做使得代码更加清晰,易于维护。

到此这篇关于浅析如何在SpringBoot中实现数据脱敏的文章就介绍到这了,更多相关SpringBoot实现数据脱敏内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java switch()括号内参数的类型要求详解

    Java switch()括号内参数的类型要求详解

    这篇文章主要介绍了Java switch()括号内参数的类型要求,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • 关于Java中ArrayList的源码分析

    关于Java中ArrayList的源码分析

    这篇文章主要从源码角度带大家深入了解一下Java中ArrayList的构造方法和属性等知识,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下
    2023-05-05
  • JDK9的新特性之String压缩和字符编码的实现方法

    JDK9的新特性之String压缩和字符编码的实现方法

    这篇文章主要介绍了JDK9的新特性之String压缩和字符编码的实现方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-05-05
  • Java超详细透彻讲解接口

    Java超详细透彻讲解接口

    接口是Java中最重要的概念之一,它可以被理解为一种特殊的类,不同的是接口的成员没有执行体,是由全局常量和公共的抽象方法所组成,本文给大家介绍Java接口,感兴趣的朋友一起看看吧
    2022-05-05
  • 利用java实现单词倒序排列

    利用java实现单词倒序排列

    这篇文章就是利用java实现单词倒序排列,感觉像是在变魔术,感兴趣的小伙伴来见证一下
    2015-07-07
  • Java中List集合去除重复数据的方法汇总

    Java中List集合去除重复数据的方法汇总

    这篇文章主要给大家介绍了关于Java中List集合去除重复数据的方法,文中通过图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-02-02
  • Java中的通用路径转义符介绍

    Java中的通用路径转义符介绍

    这篇文章主要介绍了Java中的通用路径转义符介绍,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • spring @Lazy延迟注入的逻辑实现

    spring @Lazy延迟注入的逻辑实现

    有时候我们会在属性注入的时候添加@Lazy注解实现延迟注入,今天咱们通过阅读源码来分析下原因,感兴趣的可以了解一下
    2021-08-08
  • Java ArrayList.add 的实现方法

    Java ArrayList.add 的实现方法

    这篇文章主要介绍了Java ArrayList.add 的实现方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-11-11
  • 关于SpringMVC在Controller层方法的参数解析详解

    关于SpringMVC在Controller层方法的参数解析详解

    在SpringMVC中,控制器Controller负责处理由DispatcherServlet分发的请求,下面这篇文章主要给大家介绍了关于SpringMVC在Controller层方法的参数解析的相关资料,需要的朋友可以参考下
    2021-12-12

最新评论