浅析如何在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实现数据脱敏内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!