首页 > 其他分享 >使用jackson进行数据脱敏

使用jackson进行数据脱敏

时间:2023-04-11 20:22:48浏览次数:53  
标签:jackson String class 注解 序列化 数据 public 脱敏

背景

前两天看到有人写了个jackson的数据脱敏,突然挺感兴趣的,感觉以后的开发过程中也能够用到,就照着抄了一下,顺便自己消化了一下。

目的

在服务端返回数据时,利用Jackson序列化完成数据脱敏,达到对敏感信息脱敏展示。
降低重复开发量,提升开发效率
形成统一有效的脱敏规则
可基于重写默认脱敏实现的desensitize方法,实现可扩展、可自定义的个性化业务场景的脱敏需求

参考链接

地址

前期准备

StdSerializer:所有标准序列化程序所使用的基类,这个是编写自定义序列化程序所推荐使用的基类,这边用到它的serialize方法,来做序列化转化
ContextualSerializer:是Jackson 提供的另一个序列化相关的接口,它的作用是通过字段已知的上下文信息定制JsonSerializer,调用的createContextual方法,简单来讲就是通过它注入新增的序列化对象

实现思路

1.我们首先定义一个脱敏器接口****Desensitization,定义一个脱敏方法T desensitize(T target)
2.给脱敏接口一个默认的接口实现DefaultDesensitization,不定义方法,他也是一个接口,不做实现。
3.定义一个手机号脱敏实现类MobileNoDesensitization,实现DefaultDesensitization,实现脱敏方法desensitize,做自己的脱敏处理
4.定义一个脱敏注解Desensitize,定义需要的属性,脱敏实现类desensitization
5.定义默认的脱敏注解DefaultDesensitize,在这个注解上增加脱敏注解Desensitize,并指定脱敏实现类,这里是DefaultDesensitization
6.定义手机号脱敏注解MobileNoDesensitize,在这个注解上增加脱敏注解Desensitize,并指定脱敏实现类,这里是MobileNoDesensitization
7.定义脱敏序列化器,createContextual方法通过它注入新增的序列化对象。serialize方法,来做序列化转化
8.定义脱敏工厂,根据字节码,创建对象。
9.定义脱敏符号Symbol,做替换

代码例子

1.定义一个脱敏器接口****Desensitization

/**
 * 脱敏器
 *
 * @author zhangxiaoxu15
 * @date 2022/2/8 10:56
 */
public interface Desensitization<T> {
    /**
     * 脱敏实现
     *
     * @param target 脱敏对象
     * @return 脱敏返回结果
     */
    T desensitize(T target);
}

2.接口实现DefaultDesensitization

点击查看代码

/**
 * 默认脱敏实现
 *
 * @author zhangxiaoxu15
 * @date 2022/2/8 11:01
 */
public interface DefaultDesensitization extends Desensitization<String> {
}

3.手机号脱敏实现类MobileNoDesensitization

点击查看代码

/**
 * 手机号脱敏器,保留前3位和后4位
 *
 * @author zhangxiaoxu15
 * @date 2022/2/8 11:02
 */
public class MobileNoDesensitization implements DefaultDesensitization {
    /**
     * 手机号正则
     */
    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}");


    /**
     * 手机号脱敏实现
     * @param target 脱敏对象
     * @return
     */
    @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;
    }
}

4.定义一个脱敏注解Desensitize

点击查看代码


/**
 * 脱敏注解
 *
 * @author zhangxiaoxu15
 * @date 2022/2/8 11:09
 */
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})//字段、枚举的常量,注解
@Retention(RetentionPolicy.RUNTIME)//运行时执行
@JacksonAnnotationsInside//组合注解,自定义注解需要
@JsonSerialize(using = ObjectDesensitizeSerializer.class)//指定序列化实现对象
@Documented
public @interface Desensitize {
    /**
     * 对象脱敏器实现
     */
    @SuppressWarnings("all")
    Class<? extends Desensitization<?>> desensitization();
}

5.定义默认的脱敏注解DefaultDesensitize

点击查看代码

/**
 * 默认脱敏注解
 *
 * @author zhangxiaoxu15
 * @date 2022/2/8 11:14
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@Desensitize(desensitization = DefaultDesensitization.class)
@Documented
public @interface DefaultDesensitize {

}

6.定义手机号脱敏注解MobileNoDesensitize

/**

  • 手机号脱敏注解
  • @author zhangxiaoxu15
  • @date 2022/2/8 11:18
    */
    @Target({ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    @JacksonAnnotationsInside
    @Desensitize(desensitization = MobileNoDesensitization.class)
    @Documented
    public @interface MobileNoDesensitize {
    }

7.定义脱敏序列化器,createContextual方法通过它注入新增的序列化对象。serialize方法,来做序列化转化

点击查看代码



/**
 * 脱敏序列化器
 *
 * StdSerializer:所有标准序列化程序所使用的基类,这个是编写自定义序列化程序所推荐使用的基类。
 * ContextualSerializer:是Jackson 提供的另一个序列化相关的接口,它的作用是通过字段已知的上下文信息定制JsonSerializer。
 * @author zhangxiaoxu15
 * @date 2022/2/8 11:10
 */
public class ObjectDesensitizeSerializer extends StdSerializer<Object> implements ContextualSerializer {
    private static final long serialVersionUID = -7868746622368564541L;
    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;
    }

    /**
     * 扫描到的进入序列化
     * createContextual可以获得字段的类型以及注解。当字段拥有自定义注解时,取出注解中的值创建定制的序列化方式,这样在serialize方法中便可以得到这个值了。
     * createContextual方法只会在第一次序列化字段时调用(因为字段的上下文信息在运行期不会改变),所以无需关心性能问题。
     * @param prov
     * @param property
     * @return
     */
    @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 != DefaultDesensitization.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);
        }
    }
}

8.定义脱敏工厂,根据字节码,创建对象。

点击查看代码

/**
 * 工厂方法
 *
 * @author zhangxiaoxu15
 * @date 2022/2/8 10:58
 */
public class DesensitizationFactory {
    private DesensitizationFactory() {
    }

    private static final Map<Class<?>, Desensitization<?>> map = new HashMap<>();


    @SuppressWarnings("all")
    /**
     * 通过clazz求class对象
     */
    public static Desensitization<?> getDesensitization(Class<?> clazz) {
        if (clazz.isInterface()) {
            throw new UnsupportedOperationException("desensitization is interface, what is expected is an implementation class !");
        }
        return map.computeIfAbsent(clazz, key -> {
            try {
                return (Desensitization<?>) clazz.newInstance();
            } catch (InstantiationException | IllegalAccessException e) {
                throw new UnsupportedOperationException(e.getMessage(), e);
            }
        });
    }
}

9.定义脱敏符号

点击查看代码

/**
 * 脱敏符号
 *
 * @author zhangxiaoxu15
 * @date 2022/2/8 10:53
 */
public class Symbol {
    /**
     * '*'脱敏符
     */
    public static final String STAR = "*";

    private Symbol() {
    }

    /**
     * 获取符号
     *
     * @param number 符号个数
     * @param symbol 符号
     */
    public static String getSymbol(int number, String symbol) {
        return IntStream.range(0, number).mapToObj(i -> symbol).collect(Collectors.joining());
    }
}

10.定义java bean

点击查看代码

public class Person {
    @MobileNoDesensitize
    private String moblie;
    @DefaultDesensitize
    private String name;

    public String getMoblie() {
        return moblie;
    }

    public void setMoblie(String moblie) {
        this.moblie = moblie;
    }

    public Person(String moblie, String name) {
        this.moblie = moblie;
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

执行情况

点击查看代码

@SpringBootTest
class DemoTestApplicationTests {


    /**
     * 首先定义脱敏序列化实现类ObjectDesensitizeSerializer,主要作用是获取序列化对象和实现类
     * 定义注解@Desensitize,指定序列化实现对象。绑定脱敏实现类
     * 定义手机号脱敏注解@MobileNoDesensitize,绑定脱敏实现类
     * @throws JsonProcessingException
     */
      @Test
    void contextLoads() throws JsonProcessingException {
          Person person=new Person("15927388235","12121");
          ObjectMapper objectMapper = new ObjectMapper();

          //将对象序列化为json字符串
          objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); //忽略为null的字段
          String userJsonString = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(person);
          System.out.println(userJsonString);
        System.out.println("11111111111");
    }

}

点击查看代码
{
  "moblie" : "159****8235",
  "name" : "*****"
}

标签:jackson,String,class,注解,序列化,数据,public,脱敏
From: https://www.cnblogs.com/cj8357475/p/17307405.html

相关文章

  • php的TP框架保存数据报错: SQLSTATE[HY000]: General error: 1366 Incorrect string v
    这一般情况就是保存表情字符导致的字符长度问题原因可能: (需要改字符集为 utf8mb4 排序规则为utf8mb4_general_ci)1.数据表字段不是utf8mb42.项目目录下文件.env里配置mysql  CHARSET=utf8需要该为 CHARSET=utf8mb43.如果不存在.env文件,则可能是config目......
  • flask之sqlalchemy快速插入数据-scoped_session线程安全-基本增删改查-表模型一对多-
    目录flask之sqlalchemy快速插入数据-scoped_session线程安全-基本增删改查-表模型一对多-多对多-连表查询今日内容1sqlalchemy快速插入数据2scoped_session线程安全2.1基本使用2.2加在类上的装饰器3基本增删改查3.1基本增删改查和高级查询3.2原生sql3.3django中执行原生sq......
  • jmeter数据库连接6
    1,准备资料1.一个可用的数据库2.连接数据库需要的驱动2,jmeter连接数据库3,发送插入语句请求4,发送查询语句请求5,发送删除语句请求6,对数据库进行压测本文永久更新地址:1,准备资料1.一个可用的数据库搭建一个mysql8.0的数据库环境,并设置数据库可以远程访问docker......
  • 数据链路层
        工作在数据链路层的主要网络是以太网 EthernetII是现在使用的主流IEEE802.3是EthernetII的前身(20世纪70年代)其中只有一个协议STP     主要的介质有双绞线和光纤双绞线就是网线只有一个头-水晶头光纤头分为好几种      协议类......
  • poi与excel表格数据的互转
    <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId></dependency><dependency><groupId>org.apache.poi</groupId>......
  • 数据类型
    Javascript数据类型1.数值型整型:123//十进制0123//八进制,以0开头0x123//十六进制,以0x开头浮点型:整数部分加小数部分组成,只能用十进制表示,可以科学计数法2.字符型字符型数据是使用单引号或者双引号括起来的一个或者多个字符**javascript没有cha......
  • pymysql 操作数据库
    一、数据库操作应用场景1、检验测试数据接口发送请求后明确会对数据库中的某个字段进行修改,但响应结果中无该字段数据时。如:ihrm删除员工接口。is_delete字段,没有在响应结果中出现!需要借助数据库校验!2、构造测试数据测试数据使用一......
  • Jackson常用注解
    目录Jackson常用注解序列化注解@com.fasterxml.jackson.annotation.JsonAnyGetter@com.fasterxml.jackson.annotation.JsonFormat@com.fasterxml.jackson.annotation.JsonGetter@com.fasterxml.jackson.annotation.JsonInclude@com.fasterxml.jackson.annotation.JsonIncludePrope......
  • 批处理返回Oracle的表数据
    bat:@ECHOOFFGOTOchoice:choiceECHO===============ECHO选择要查询的系统ECHO1.准生产集中ECHO2.准生产两融ECHO3.准生产一柜通ECHO4.仿真集中ECHO5.仿真两融ECHO6.仿真一柜通ECHO===============SET/pa=输入数字:IF%a%==1GOTO1IF%a%==2GOTO2IF......
  • js 8种数据类型
    1、ES6之前共6种:number\string\Boolean\null\undefined\object;ES6增加symbol:这种类型的对象永不相等,可以解决属性名冲突的问题,做为标记。ES11增加bigint:写法:1234555n,是指安全存储、操作大整数(不可用于浮点数操作);2、增加bigint的原因:解决number大整数精度丢失问题;J......