Java利用Jackson序列化实现数据脱敏

 更新时间:2021年10月13日 09:54:23   作者:EalenXie  
这篇文章主要介绍了利用Jackson序列化实现数据脱敏,首先在需要进行脱敏的VO字段上面标注相关脱敏注解,具体实例代码文中给大家介绍的非常详细,需要的朋友可以参考下

几天前使用了Jackson对数据的自定义序列化。突发灵感,利用此方法来简单实现接口返回数据脱敏,故写此文记录。

核心思想是利用Jackson的StdSerializer,@JsonSerialize,以及自己实现的数据脱敏过程。

使用效果如下:

首先在需要进行脱敏的VO字段上面标注相关脱敏注解

调用接口即可看到脱敏效果

实现过程如下:

1. 定义脱敏的过程实现

/**
 * Created by EalenXie on 2021/9/24 15:52
 * 顶级的脱敏器
 */
public interface Desensitization<T> {

    /**
     * 脱敏实现
     *
     * @param target 脱敏对象
     * @return 脱敏返回结果
     */
    T desensitize(T target);

}

比如具体的手机号脱敏器实现

import com.github.Symbol;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by EalenXie on 2021/9/24 15:56
 * 手机号脱敏器 默认只保留前3位和后4位
 */
public class PhoneDesensitization implements StringDesensitization {

    /**
     * 手机号正则
     */
    private static final Pattern DEFAULT_PATTERN = Pattern.compile("(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\d{8}");

    /**
     * 手机号脱敏 只保留前3位和后4位
     */
    @Override
    public String desensitize(String target) {
        Matcher matcher = DEFAULT_PATTERN.matcher(target);
        while (matcher.find()) {
            String group = matcher.group();
            target = target.replace(group, group.substring(0, 3) + Symbol.getSymbol(4, Symbol.STAR) + group.substring(7, 11));
        }
        return target;
    }
}

2.定义脱敏注解,并指明了使用的序列化器,注解中声明了使用的脱敏器实现

package com.github.annotation;

import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.github.desensitization.Desensitization;
import com.github.serializer.ObjectDesensitizeSerializer;

import java.lang.annotation.*;

/**
 * Created by EalenXie on 2021/10/8 11:30
 */
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = ObjectDesensitizeSerializer.class)
@Documented
public @interface Desensitize {
    /**
     * 脱敏器实现
     */
    @SuppressWarnings("all")
    Class<? extends Desensitization<?>> desensitization();
}

3. 实现定义的序列化器

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.github.Symbol;
import com.github.annotation.Desensitize;
import com.github.desensitization.Desensitization;
import com.github.desensitization.DesensitizationFactory;
import com.github.desensitization.StringDesensitization;

import java.io.IOException;

/**
 * Created by EalenXie on 2021/8/9 9:03
 * 脱敏序列化器
 */
public class ObjectDesensitizeSerializer extends StdSerializer<Object> implements ContextualSerializer {

    private transient Desensitization<Object> desensitization;

    protected ObjectDesensitizeSerializer() {
        super(Object.class);
    }

    public Desensitization<Object> getDesensitization() {
        return desensitization;
    }

    public void setDesensitization(Desensitization<Object> desensitization) {
        this.desensitization = desensitization;
    }

    @Override
    public JsonSerializer<Object> createContextual(SerializerProvider prov, BeanProperty property) {
        Desensitize annotation = property.getAnnotation(Desensitize.class);
        return createContextual(annotation.desensitization());
    }

    @SuppressWarnings("unchecked")
    public JsonSerializer<Object> createContextual(Class<? extends Desensitization<?>> clazz) {
        ObjectDesensitizeSerializer serializer = new ObjectDesensitizeSerializer();
        if (clazz != StringDesensitization.class) {
            serializer.setDesensitization((Desensitization<Object>) DesensitizationFactory.getDesensitization(clazz));
        }
        return serializer;
    }

    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        Desensitization<Object> objectDesensitization = getDesensitization();
        if (objectDesensitization != null) {
            try {
                gen.writeObject(objectDesensitization.desensitize(value));
            } catch (Exception e) {
                gen.writeObject(value);
            }
        } else if (value instanceof String) {
            gen.writeString(Symbol.getSymbol(((String) value).length(), Symbol.STAR));
        } else {
            gen.writeObject(value);
        }
    }
}

4.代码的设计说明

完整代码可见 : https://github.com/EalenXie/jackson-desensitize

另附 基于Logback的日志脱敏方案(笔者认为这可能是全网最简单快捷的)

原理是利用Logback的自定义日志转换器ClassicConverter

1. 自定义脱敏日志转换器

import ch.qos.logback.classic.pattern.ClassicConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import com.github.desensitization.EmailDesensitization;
import com.github.desensitization.IDCardDesensitization;
import com.github.desensitization.PhoneDesensitization;
import com.github.desensitization.StringDesensitization;

import java.util.ArrayList;
import java.util.List;


/**
 * @author EalenXie create on 2021/3/18 10:07
 * 此Converter提供支持日志脱敏
 * 1. 编写此LogbackDesensitizeConverter
 * 2. 正则脱敏 手机号/邮箱/身份证
 */
public class LogbackDesensitizeConverter extends ClassicConverter {

    protected static final List<StringDesensitization> DESENSITIZATION_LIST = new ArrayList<>();

    static {
        // 手机号脱敏
        DESENSITIZATION_LIST.add(new PhoneDesensitization());
        // 邮箱脱敏
        DESENSITIZATION_LIST.add(new EmailDesensitization());
        // 身份证脱敏
        DESENSITIZATION_LIST.add(new IDCardDesensitization());
    }

    @Override
    public String convert(ILoggingEvent event) {
        String content = event.getMessage();
        try {
            for (StringDesensitization desensitization : DESENSITIZATION_LIST) {
                content = desensitization.desensitize(content);
            }
        } catch (Exception e) {
            // ig
        }
        return content;
    }
}

2. 启动类为PatternLayout的静态变量defaultConverterMap新增此自定义转换器

import ch.qos.logback.classic.PatternLayout;
import com.github.filter.LogbackDesensitizeConverter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * @author EalenXie create on 2020/11/24 14:16
 */
@EnableDiscoveryClient
@SpringBootApplication
public class ApiGatewayApplication {
    public static void main(String[] args) {
        // 日志处理方案 新增一个Logback的日志脱敏转换器
        PatternLayout.defaultConverterMap.put("m", LogbackDesensitizeConverter.class.getName());
        SpringApplication.run(ApiGatewayApplication.class, args);
    }
}

启动后可以看到日志脱敏效果。

到此这篇关于利用Jackson序列化实现数据脱敏的文章就介绍到这了,更多相关Jackson序列化数据脱敏内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Spring Boot中使用Redis实战案例

    Spring Boot中使用Redis实战案例

    redis作为一个高性能的内存数据库,如果不会用就太落伍了,之前在 node.js中用过 redis,本篇记录如何将 redis 集成到 spring boot 中,下面这篇文章主要给大家介绍了关于Spring Boot中使用Redis的相关资料,需要的朋友可以参考下
    2023-04-04
  • mybatis 传入null值的解决方案

    mybatis 传入null值的解决方案

    这篇文章主要介绍了mybatis 传入null值的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • 关于Spring的统一功能处理(拦截器)实现

    关于Spring的统一功能处理(拦截器)实现

    这篇文章主要介绍了关于Spring的统一功能处理(拦截器)实现,每个方法中都要单独写用户登录验证的方法,即使封装成公共方法,也一样要传参调用和在方法中进行判断,需要的朋友可以参考下
    2023-05-05
  • Idea为java程序添加启动参数(含:VM options、Program arguments、Environment variable)

    Idea为java程序添加启动参数(含:VM options、Program arguments、Environme

    设置启动参数的意义就是当启动程序时,程序会优先读取idea的配置参数,这样就可以不用修改配置文件,下面这篇文章主要给大家介绍了关于Idea为java程序添加启动参数(含:VM options、Program arguments、Environment variable)的相关资料,需要的朋友可以参考下
    2022-12-12
  • Java中对象数组的使用方法详解

    Java中对象数组的使用方法详解

    这篇文章主要介绍了Java中对象数组的使用方法,结合实例形式分析了java对象数组的功能、定义、初始化与相关使用技巧,需要的朋友可以参考下
    2019-08-08
  • SpringBoot(JAVA)整合微信公众号消息推送完整步骤(文本、图片/视频推送)

    SpringBoot(JAVA)整合微信公众号消息推送完整步骤(文本、图片/视频推送)

    微信公众号消息推送包括文本推送和图文/视频推送两类,文本推送通过模板消息或自定义消息实现,而图文/视频推送需先上传素材至临时/永久素材库,再上传图文消息,最后进行消息推送,文中将实现的方法介绍的非常详细,需要的朋友可以参考下
    2024-09-09
  • Jmeter post上传文件实现过程详解

    Jmeter post上传文件实现过程详解

    这篇文章主要介绍了Jmeter post上传文件实现过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08
  • Spring Boot调用 Shell 脚本实现看门狗功能

    Spring Boot调用 Shell 脚本实现看门狗功能

    这篇文章主要介绍了Spring Boot调用 Shell 脚本实现看门狗功能,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-06-06
  • Java Iterator迭代器_动力节点Java学院整理

    Java Iterator迭代器_动力节点Java学院整理

    迭代器是一种模式,它可以使得对于序列类型的数据结构的遍历行为与被遍历的对象分离,接下来通过本文给大家分享Java Iterator迭代器_动力节点Java学院整理,需要的朋友参考下吧
    2017-05-05
  • Java的Spring框架中DAO数据访问对象的使用示例

    Java的Spring框架中DAO数据访问对象的使用示例

    这篇文章主要介绍了Java的Spring框架中DAO数据访问对象的使用示例,分为在Spring中DOA与JDBC以及与Hibernate的配合使用两种情况来进行演示,需要的朋友可以参考下
    2016-03-03

最新评论