springboot jackson实现脱敏

一定概率上,数据脱敏在实际项目中会有应用,如图

image

基于jackson的JsonSerialize实现可插拔的数据脱敏

代码如下:

import cn.hutool.core.util.DesensitizedUtil;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;

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

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside
@JsonSerialize(using = SensitiveSerialize.class)
public @interface Sensitive {
    DesensitizedUtil.DesensitizedType type();
}

import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.StrUtil;
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 lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Objects;

@NoArgsConstructor
@AllArgsConstructor
public class SensitiveSerialize extends JsonSerializer<String> implements ContextualSerializer {

    /**
     * 脱敏类型
     */
    private DesensitizedUtil.DesensitizedType desensitizedType;

    private boolean sensitive() {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        return StrUtil.isNotBlank(request.getHeader("sensitive"));
    }

    @Override
    public void serialize(String origin, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        if (this.sensitive()) {
            jsonGenerator.writeString(DesensitizedUtil.desensitized(origin, desensitizedType));
        } else {
            jsonGenerator.writeString(origin);
        }
    }

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
        if (Objects.equals(beanProperty.getType().getRawClass(), String.class)) {
            Sensitive sensitive = beanProperty.getAnnotation(Sensitive.class);
            if (sensitive == null) {
                sensitive = beanProperty.getContextAnnotation(Sensitive.class);
            }
            if (sensitive != null) {
                return new SensitiveSerialize(sensitive.type());
            }
            return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
        }
        return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
    }
}

使用时候,只需要在返回的实体字段上加注解即可,@Sensitive(type = DesensitizedUtil.DesensitizedType.MOBILE_PHONE)

至于脱敏的方法以及枚举都是直接采用的hutools信息脱敏工具-DesensitizedUtil,避免重复造轮子