springboot通过注解实现脱敏【未使用过过滤器形式】

0、原理
通过创建bean,实现自定义的json转换Jackson2ObjectMapperBuilder
通过此对象去serializers转换,内部通过继承StdSerializer泛化接口,实现定制的序列化操作

1、定义注解

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DesensitizedIdCard {

}

2、定义脱敏序列化

import static java.util.stream.Collectors.toMap;

/**
 * 脱敏序列化
 */
public class DesensitizeSerialize extends StdSerializer<Desensitized> {

    public static Map<Class, DesensitizeService> mapper = new HashMap<>();

    static {
        mapper.put(DesensitizedIdCard.class,new DesensitizeServiceIdCardImpl());
        mapper.put(DesensitizedName.class,new DesensitizeServiceNameImpl());
        mapper.put(DesensitizedTel.class,new DesensitizeServiceTelImpl());
    }
    protected DesensitizeSerialize() {
        super(Desensitized.class);
    }

    /**
     * 定制序列化
     */
    @Override
    public void serialize(Desensitized bean, JsonGenerator gen, SerializerProvider provider) throws IOException {
        //处理序列化
        Map<String, Object> properties = beanProperties(bean);
        gen.writeStartObject();
        for (Map.Entry<String, Object> entry : properties.entrySet()) {
            gen.writeObjectField(entry.getKey(), entry.getValue());
        }
        gen.writeEndObject();
    }

    /**
     * 解析对象属性
     *
     * @param bean
     * @return
     */
    private Map<String, Object> beanProperties(Object bean) {
        try {
            return Arrays.stream(Introspector.getBeanInfo(bean.getClass(), Object.class).getPropertyDescriptors())
                    .filter(descriptor -> Objects.nonNull(descriptor.getReadMethod()))
                    .flatMap(descriptor -> {
                        String name = descriptor.getName();
                        Method getter = descriptor.getReadMethod();
                        Object value = ReflectionUtils.invokeMethod(getter, bean);
                        if (null == value) {
                            //null不进行转化
                            return null;
                        }
                        DesensitizeService desensitizeService = getDesensitizer(bean, descriptor.getName());
                        if (null != desensitizeService) {
                            value = desensitizeService.option(String.valueOf(value));
                        }
                        Property originalProperty = new Property(name, value);

                        return Stream.of(originalProperty);
                    })
                    .collect(toMap(Property::getName, Property::getValue));
        } catch (Exception e) {
            return Collections.emptyMap();
        }
    }

    /**
     * 根据属性获取Annotation
     */
    private Annotation[] getAnnotations(Object bean, String property) {
        try {
            Field field = bean.getClass().getDeclaredField(property);
            return field.getAnnotations();
        } catch (NoSuchFieldException e) {
            return new Annotation[]{};
        }
    }

    private DesensitizeService getDesensitizer(Object bean, String property) {
        Annotation[] annotations = getAnnotations(bean, property);
        DesensitizeService desensitizer = null;
        for (Annotation ano : annotations) {
            desensitizer = mapper.get(ano.annotationType());
            if (null != desensitizer) {
                break;
            }

        }
        return desensitizer;
    }

    /**
     * 属性对应值
     */
    private class Property {
        private String name;
        private Object value;

        public Property(String name, Object value) {
            this.name = name;
            this.value = value;
        }

        public String getName() {
            return name;
        }

        public Object getValue() {
            return value;
        }
    }

}

3、定义脱敏接口

public interface DesensitizeService {
    String NULL = "null";
    String option(String value);

}

4、脱敏实现类

/**
 * 身份证脱敏
 * 规则:显示最后四位,其他隐藏。共计18位或者15位,比如:*************1234,容错处理:处理内容为空,返回原值
 */
public class DesensitizeServiceIdCardImpl implements DesensitizeService {

    @Override
    public String option(String idCard) {
        if (StringUtils.isBlank(idCard) || NULL.equals(idCard)) {
            return idCard;
        }
        String num = StringUtils.right(idCard, 4);
        return StringUtils.leftPad(num, StringUtils.length(idCard), "*");
    }
}

5、定义脱敏对外提供的接口,(哪个类需要脱敏直接实现后加入对应注解即可)

public interface Desensitized {
}

6、配置扩展脱敏

@Slf4j
@Configuration
public class DesensitizeConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public Jackson2ObjectMapperBuilder mapperBuilder() {
        log.debug("desensitize Configuration 脱敏配置");
        Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder = new Jackson2ObjectMapperBuilder();
        jackson2ObjectMapperBuilder.serializers(new DesensitizeSerialize());
        return jackson2ObjectMapperBuilder;
    }
}

7、实例

@Getter
@Setter
@ToString
public class TestDTO implements Serializable, Desensitized {
    private String id;
    private String type;
    private String pic;
    @DesensitizedName
    private String name;
    @DesensitizedIdCard
    private String idCard;
    @DesensitizedTel
    private String tel;
}

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot实现自定义注解脱敏,可以按照以下步骤进行操作: 1. 创建一个自定义注解类,在该类上使用`@Target`、`@Retention`等元注解进行注解的定义。注解中可以包含一些属性,用来指定脱敏的方式或类型。 引用 2. 在需要进行脱敏的字段上,使用刚刚定义的自定义注解进行标记。可以在实体类的字段上加上该注解,或者在需要脱敏的方法上加上该注解。 引用 3. 创建一个拦截器或者切面类,在请求进入时,通过反射机制获取到带有自定义注解的字段,并对其进行脱敏处理。脱敏的方式可以根据注解中指定的类型来进行处理。 引用 4. 在Spring Boot的配置文件(例如application.yml)中配置相关信息,如服务器端口、数据库连接信息等。 引用 通过以上步骤,就可以在Spring Boot项目中实现自定义注解脱敏的功能了。自定义注解可以帮助我们标记需要脱敏的字段,然后在拦截器或切面中实现脱敏逻辑,保护敏感数据的安全性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [springboot 自定义注解实现数据脱敏](https://blog.csdn.net/a2365900668/article/details/120306728)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值