Java 自定义脱敏注解实现

自定义注解

package com.yunmeng.iot.common.desensitization.annotation;

import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.yunmeng.iot.common.desensitization.enums.SecretStrategy;
import com.yunmeng.iot.common.desensitization.strategy.StringSecretSerializer;

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

/**
 * 自定义字符串脱敏注解
 *
 * @author Linzj
 * @date 2023/8/9/009 17:42
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = StringSecretSerializer.class)
public @interface StringSecret {

    /**
     * 脱敏策略
     *
     * @return 结果
     */
    SecretStrategy strategy();

}

脱敏策略

package com.yunmeng.iot.common.desensitization.enums;

import lombok.Getter;

import java.util.function.Function;

/**
 * 脱敏策略,不同数据可选择不同的策略
 *
 * @author Linzj
 * @date 2023/8/9/009 17:57
 */
@Getter
public enum SecretStrategy {

    /**
     * 用户名脱敏
     */
    USERNAME(str -> str.replaceAll("(\\S)\\S(\\S*)", "$1*$2")),

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

    /**
     * 手机号脱敏
     */
    PHONE(str -> str.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")),

    /**
     * 地址脱敏
     */
    ADDRESS(str -> str.replaceAll("(\\S{3})\\S{2}(\\S*)\\S{2}", "$1****$2****"));

    private final Function<String, String> desensitizer;

    SecretStrategy(Function<String, String> desensitizer) {
        this.desensitizer = desensitizer;
    }
}

序列化器实现

package com.yunmeng.iot.common.desensitization.strategy;

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.yunmeng.iot.common.desensitization.annotation.StringSecret;
import com.yunmeng.iot.common.desensitization.enums.SecretStrategy;

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

/**
 * 字符串类型序列化器实现
 *
 * @author Linzj
 * @date 2023/8/9/009 17:43
 */
public class StringSecretSerializer extends JsonSerializer<String> implements ContextualSerializer {

    private SecretStrategy secretStrategy;

    /**
     * 步骤一
     * 方法来源于ContextualSerializer,获取属性上的注解属性,同时返回一个合适的序列化器
     */
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
        // 获取自定义注解
        StringSecret annotation = beanProperty.getAnnotation(StringSecret.class);
        // 注解不为空,且标注的字段为String
        if (Objects.nonNull(annotation) && Objects.equals(String.class, beanProperty.getType().getRawClass())) {
            this.secretStrategy = annotation.strategy();
            // 符合我们自定义情况,返回本序列化器,将顺利进入到该类中的serialize()方法中
            return this;
        }
        // 注解为空,字段不为String,寻找合适的序列化器进行处理
        return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
    }

    /**
     * 步骤二
     * 方法来源于JsonSerializer<String>:指定返回类型为String类型,serialize()将修改后的数据返回
     */
    @Override
    public void serialize(String s, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        if (Objects.isNull(secretStrategy)) {
            // 定义策略为空,返回原字符串
            jsonGenerator.writeString(s);
        } else {
            // 定义策略不为空,返回策略处理过的字符串
            jsonGenerator.writeString(secretStrategy.getDesensitizer().apply(s));
        }
    }
}
posted @ 2023-10-21 11:13  启航黑珍珠号  阅读(48)  评论(0)    收藏  举报