Jackson注解自定义数据脱敏策略

1.前言

有时候,我们返回给前端的数据需要脱敏,避免用户信息被泄漏,就像你点外卖一样,京东或淘宝购物一样,手机号,姓名这些字段是被脱敏后的,在这个大数据时代,用户的数据安全是及其重要的。我们如何对用户统一数据进行脱敏处理呢?如果我们自定义脱敏方式,使用一个工具类,被改字段传递进去,脱敏后返回新的字符串,那这样是很多地方需要手动去编写很多重复的代码,而且不利于维护,比如是单个bean,或者是list的时候还要去遍历一次list。有没有什么方法统一处理呢?我们定义好脱敏规则,只需要在需要脱敏的字段上加上一个注解即可。那当然是可以的

2.脱敏注解

import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.springboot.example.desensitizer.handler.SensitiveJsonSerialize;
import com.springboot.example.desensitizer.enums.SensitiveStrategy ;

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

/**
 * 脱敏注解
 * @author compass
 * @date 2022-12-11
 * @since 1.0
 **/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside
@JsonSerialize(using = SensitiveJsonSerialize.class)
public @interface Sensitive {

    SensitiveStrategy strategy();
}

3.定义好一套需要脱敏的规则

import java.util.function.Function;

/**
 * 对需要特别脱敏的字段指定脱敏规则
 * @author compass
 * @date 2022-12-11
 * @since 1.0
 **/
public enum SensitiveStrategy {
    /**
     * 对用户名进行脱敏,基于正则表达式实现
     */
    USERNAME(s -> s.replaceAll("(\\S)\\S(\\S*)", "$1*$2")),

    /**
     * 对身份证进行脱敏
     */
    ID_CARD(s -> s.replaceAll("(\\d{4})\\d{10}(\\w{4})", "$1****$2")),

    /**
     * 对电话号码进行脱敏
     */
    PHONE(s -> s.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")),

    /**
     * 对地址进行脱敏
     */
    ADDRESS(s -> s.replaceAll("(\\S{3})\\S{2}(\\S*)\\S{2}", "$1****$2****")),

    /**
     * 对密码进行脱敏,全部加密即可
     */
    PASSWORD(s -> "********");


    private final Function<String, String> desensitizeSerializer;

    SensitiveStrategy(Function<String, String> desensitizeSerializer) {
        this.desensitizeSerializer = desensitizeSerializer;
    }

    // 用于后续获取脱敏的规则,实现脱敏
    public  Function<String, String> desensitizeSerializer() {
        return desensitizeSerializer;
    }


}

4.自定义JSON序列化

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.springboot.example.desensitizer.annotations.Sensitive;
import com.springboot.example.desensitizer.enums.SensitiveStrategy;

import java.io.IOException;
import java.util.Objects;

/**
 * @author compass
 * @date 2022-12-11
 * @since 1.0
 **/
public class SensitiveJsonSerialize  extends JsonSerializer<String> implements ContextualSerializer {

    private SensitiveStrategy strategy;

    // 在序列化时进行数据脱敏
    @Override
    public void serialize(String value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {

        jsonGenerator.writeString(strategy.desensitizeSerializer().apply(value));
    }

    // 获取注解上的属性
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider provider, BeanProperty property) throws JsonMappingException {
        Sensitive annotation = property.getAnnotation(Sensitive.class);
        if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass())) {
            // 主要代码在这里,获取脱敏的规则
            this.strategy = annotation.strategy();
            return this;
        }
        return provider.findValueSerializer(property.getType(), property);

    }
}

5.在实体类上标注对应的脱敏规则

@Data
@ToString
public class Employee {
    private Long id;

    @Sensitive(strategy = SensitiveStrategy.USERNAME)
    private String name;

    private String email;

    @Sensitive(strategy = SensitiveStrategy.ID_CARD)
    private String identity;

    @Sensitive(strategy = SensitiveStrategy.PASSWORD)
    private String password;

    @Sensitive(strategy = SensitiveStrategy.PHONE)
    private String phone;

    private Date birthday;

    private String jobNumber;

    private Boolean verified;

    @Sensitive(strategy = SensitiveStrategy.ADDRESS)
    private String address;

}

5.写一个接口进行测试

@RestController
@RequestMapping("/sensitiveStrategy")
public class SensitiveStrategyController {

    @GetMapping("/v1/getSensitiveStrategy")
    public ResponseResult<Employee> getSensitiveStrategy() {
        Employee employee = new Employee();
        employee.setId(IdUtil.getSnowflakeNextId());
        employee.setName("诸葛亮");
        employee.setEmail("360369395@qq.com");
        employee.setIdentity("522132188881017455X");
        employee.setPassword("");
        employee.setPhone("17785444960");
        employee.setBirthday(new Date());
        employee.setJobNumber(IdUtil.getSnowflake().nextIdStr());
        employee.setVerified(false);
        employee.setAddress("重庆市沙坪坝区大学城中路2-18号");

        return ResponseResult.success("请求成功", employee);
    }
}

调用我们写的测试接口,可以看到,我们的接口都做了脱敏处理

image-20221211191012694

调用我们写的测试接口,可以看到,我们的接口都做了脱敏处理

阅读终点,创作起航,您可以撰写心得或摘录文章要点写篇博文。去创作
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: Jackson是一个Java库,用于将Java对象序列化为JSON格式和反序列化为Java对象。要自定义Jackson的反序列化器,可以使用@JsonDeserialize注解并传入自定义反序列化器类,如下所示: ``` @JsonDeserialize(using = MyDeserializer.class) public class MyObject { // class fields and methods } ``` MyDeserializer类需要继承com.fasterxml.jackson.databind.JsonDeserializer<T>,并重写deserialize()方法实现自定义反序列化逻辑。 ``` public class MyDeserializer extends JsonDeserializer<MyObject> { @Override public MyObject deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { // custom deserialization logic } } ``` 注意: 类需要添加 Jackson 依赖 ``` <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.11.3</version> </dependency> ``` ### 回答2: 要自定义Jackson的反序列化器,可以按照以下步骤操作: 1. 创建自定义反序列化器类:首先创建一个新的类,实现Jackson提供的`JsonDeserializer`接口。该接口要求实现`deserialize`方法,该方法将负责将JSON数据转换为目标Java对象。 2. 实现`deserialize`方法:在`deserialize`方法中,根据需要的逻辑解析JSON数据并创建目标对象,并将其返回。 3. 注册自定义反序列化器:在使用Jackson的代码中,需要将自定义反序列化器注册到`ObjectMapper`中,以便在反序列化时使用。可以使用`SimpleModule`类创建一个新的模块,并使用`addDeserializer`方法将自定义反序列化器与目标类型关联起来。然后,使用`registerModule`方法将模块注册到`ObjectMapper`中。 4. 使用自定义反序列化器:在需要使用自定义反序列化器的代码中,创建`ObjectMapper`实例,并执行反序列化操作。在反序列化时,Jackson将自动选择正确的反序列化器进行处理。 通过以上步骤,我们可以自定义Jackson的反序列化器,并在需要时将其应用于特定的对象类型。这样可以根据自定义的逻辑将JSON数据转换为目标对象,使得反序列化的过程更加灵活和个性化。 ### 回答3: 要自定义 Jackson 反序列化器,你可以按照以下步骤进行操作: 1. 创建一个类,并实现 Jackson 的 `JsonDeserializer` 接口。这个接口要求你实现 `deserialize` 方法,用于自定义对象的反序列化逻辑。 2. 在 `deserialize` 方法中,你可以根据需要读取 JSON 中的属性并进行处理。你可以使用 Jackson 的 `JsonParser` 对象来读取 JSON 数据。 3. 根据 JSON 中的属性,你可以创建一个自定义的对象,并将属性值填充进去。 4. 在自定义对象中,你可以添加任何你需要的验证逻辑,以确保对象的属性是有效的。 5. 最后,返回你自定义的对象。 6. 使用自定义的反序列化器,你可以为 Jackson 提供一个 `ObjectMapper`,并使用 `registerModule` 方法注册你的自定义模块。 以下是一个示例代码,用来自定义一个反序列化器: ```java public class CustomDeserializer extends JsonDeserializer<CustomObject> { @Override public CustomObject deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { JsonNode jsonNode = jsonParser.getCodec().readTree(jsonParser); // 从 JSON 中读取属性 String property1 = jsonNode.get("property1").asText(); int property2 = jsonNode.get("property2").asInt(); // 创建自定义对象并填充属性 CustomObject customObject = new CustomObject(); customObject.setProperty1(property1); customObject.setProperty2(property2); // 进行一些验证逻辑 if (customObject.getProperty1() == null || customObject.getProperty1().isEmpty()) { throw new IOException("Invalid value for property1"); } return customObject; } } ``` 使用自定义的反序列化器,你可以在 ObjectMapper 中注册你的自定义模块: ```java ObjectMapper objectMapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); module.addDeserializer(CustomObject.class, new CustomDeserializer()); objectMapper.registerModule(module); CustomObject customObject = objectMapper.readValue(jsonString, CustomObject.class); ``` 通过以上步骤,你就可以成功自定义 Jackson 的反序列化器,并根据你的需求对对象进行反序列化操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

野生java研究僧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值