java后端数据脱敏看这一篇就够了.

背景说明

    现在的项目中需要对展示的数据进行脱敏处理,类似的场景很常见,比如说展示的手机号、银行卡、用户姓名等全部用***这类的特殊字符进行代替。我们的项目就需要将岗位展示列表中的用户岗位发布姓名全部用星号进行替换.最初的时候是入门级版本,几行代码就可以实现。后期对项目进行优化,考虑到脱敏的场景以及脱敏的形式可能会变化(比如说手机号脱敏要求前面三位后两位之外的进行脱敏,用户姓名要求全部脱敏处理),所以对原有逻辑进行了修改,于是有了进阶版实现方式,优点在于对脱敏业务与序列化处理进行解耦,便于拓展和后期维护,下面就具体说下处理过程,希望对有同样需求的同学有所帮助!

入门级处理

    场景:将岗位查询列表中的用户姓名进行全部脱敏处理,使用三个星号进行代替.直接上代码:
实体类ShopPostInfo:

public class ShopPostInfo implements Serializable {
    private static final long serialVersionUID = -2040496864515327697L;

  
    // 数据脱敏处理,用户名全部替换为***
   @JsonSerialize(using = DesensitizationSerializer.class)
    private String userName;

// 省略其他信息
}

自定义脱敏处理器DesensitizationSerializer:

public class DesensitizationSerializer extends JsonSerializer<String>  {

    // 序列化处理
    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        // 脱敏成***
        gen.writeString("***");
    }
    }

脱敏后截图:
在这里插入图片描述
    可以看到用户的姓名都已经被处理成***了.到这里问题是解决了,但是后期再有其他的脱敏需求怎么办,比如说想对手机号进行脱敏处理,只想对前三位后两位之外的数字进行脱敏处理怎么办?重新定义一个手机号脱敏处理器?那以后需要维护的脱敏类会越来越多,显得会有所冗余,毕竟每种脱敏处理器中仅有脱敏策略不同,是否可以只专注于脱敏策略的实现,对于序列化的实现进行统一处理.基于上面的疑问就有了脱敏处理的进阶版,请往下看!

进阶版处理

自定义脱敏注解

@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = DesensitizationSerializer.class)
public @interface DesensitizationAnnotation {

    Class<? extends DesensitizationStrategy> strategy();
}

自定义脱敏注解序列化处理器

public class DesensitizationSerializer extends JsonSerializer<String> implements ContextualSerializer {

    // 脱敏处理策略
    private DesensitizationStrategy desensitizationStrategy;

    public DesensitizationSerializer() {
    }

    public DesensitizationSerializer(DesensitizationStrategy desensitizationStrategy) {
        this.desensitizationStrategy = desensitizationStrategy;
    }

    // 序列化核心处理
    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        int a=0;
        // 脱敏处理公共逻辑
        String desensitizationValue = desensitizationStrategy.desensitizationHandle(value);
        // 序列化处理公共方案
        gen.writeString(desensitizationValue);
    }

    // 设置自定义脱敏策略:desensitizationSerializer
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
        JsonSerializer<?> desensitizationSerializer = null;
        if(null == property) desensitizationSerializer = prov.findNullValueSerializer(property);

        if(!Objects.equals(property.getType().getRawClass(), String.class))
            desensitizationSerializer = prov.findValueSerializer(property.getType(), property);

        if(Objects.equals(property.getType().getRawClass(), String.class)){
            // JsonSerializer设置自定义脱敏策略
            desensitizationSerializer = handleDesensitizationSerializer(desensitizationSerializer, property);
        }
        return desensitizationSerializer;
    }

    // 脱敏设置
    private JsonSerializer<?> handleDesensitizationSerializer(JsonSerializer<?> desensitizationSerializer, BeanProperty beanProperty) {
        // 获取脱敏注解
        DesensitizationAnnotation desensitizationJsonSerializer = beanProperty.getAnnotation(DesensitizationAnnotation.class);

        if (desensitizationJsonSerializer == null) desensitizationJsonSerializer = beanProperty.getContextAnnotation(DesensitizationAnnotation.class);

        // 设置脱敏实例,添加自定义脱敏策略
        if (desensitizationJsonSerializer != null) {
            try {
                desensitizationSerializer = new DesensitizationSerializer(desensitizationJsonSerializer.strategy().newInstance());
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return desensitizationSerializer;
    }
}

实体类中添加序列化处理器

public class ShopPostInfo implements Serializable {
    private static final long serialVersionUID = -2040496864515327697L;

  
    // modify by txm 2022/10/4 数据脱敏处理
    // @JsonSerialize(using = DesensitizationSerializer.class)
    @DesensitizationAnnotation(strategy = FullSensitization.class)
    private String userName;

// 省略其他信息
}

全部脱敏处理策略:

public class FullSensitization implements DesensitizationStrategy{

    // 全脱敏处理
    @Override
    public String desensitizationHandle(String oldValue) {
        return "***";
    }
}

指定格式脱敏策略,这里指定只对用户姓名第一个字以外进行脱敏处理(暂时没想出更合理的脱敏场景,能理解要优化的点就行)

public class PatternDeSensitization implements DesensitizationStrategy{

    // 部分脱敏处理,首个字符处理,其余都脱敏.这里使用的hutool中的strUtil工具类,直接使用string原生的方法也可以.
    @Override
    public String desensitizationHandle(String oldValue) {
        return StrUtil.replace(oldValue,1,oldValue.length(),'*');
    }

}

测试结果:
    全部脱敏实现效果:
在这里插入图片描述

    部分脱敏实现效果:
在这里插入图片描述
    以上是关于数据脱敏的实现方式,其中根据业务需求做了一下结构优化,如果有相同的业务需求,看完希望对你有帮助,欢迎评论区留言点赞!

  • 0
    点赞
  • 6
    收藏
  • 打赏
    打赏
  • 0
    评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:游动-白 设计师:我叫白小胖 返回首页
评论

打赏作者

卖柴火的小伙子

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

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值