一个注解搞定接口返回数据脱敏

2023-05-16

下午惬意时光,突然产品小姐姐走到我面前,打断我短暂的摸鱼time,企图与我进行深入交流,还好我早有防备没有闪,打开瑞star的点单页面,暗示没有一杯coffee解决不了的需求,需求是某些接口返回的信息,涉及到敏感数据的必须进行脱敏操作,我思考一反,表示某问题,马上安排。

思路

1.要做成可配置多策略的脱敏操作,要不然一个个接口进行脱敏操作,重复的工作量太多,很显然违背了“多写一行算我输”的程序员规范,思来想去,定义数据脱敏注解和数据脱敏逻辑的接口, 在返回类上,对需要进行脱敏的属性加上,并指定对应的脱敏策略操作。

2.接下来我只需要拦截控制器返回的数据,找到带有脱敏注解的属性操作即可,一开始打算用@ControllerAdvice去实现,但发现需要自己去反射类获取注解,当返回对象比较复杂,需要递归去反射,性能一下子就会降低,于是换种思路,我想到平时使用的@JsonFormat,跟我现在的场景很类似,通过自定义注解跟字段解析器,对字段进行自定义解析,tql

代码

1. 自定义数据注解,并可以配置数据脱敏策略


@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataMasking {

    DataMaskingFunc maskFunc() default DataMaskingFunc.NO_MASK;

}

2. 自定义Serializer,参考jackson的StringSerializer,下面的示例只针对String类型进行脱敏



public interface DataMaskingOperation {

    String MASK_CHAR = "*";
    
    String mask(String content, String maskChar);

}

public enum DataMaskingFunc {

     /**
     *  脱敏转换器
     */
     NO_MASK((str, maskChar) -> {
        return str;
     }),
     ALL_MASK((str, maskChar) -> {
        if (StringUtils.hasLength(str)) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < str.length(); i++) {
                sb.append(StringUtils.hasLength(maskChar) ? maskChar : DataMaskingOperation.MASK_CHAR);
            }
            return sb.toString();
        } else {
            return str;
        }
    });

    private final DataMaskingOperation operation;

    private DataMaskingFunc(DataMaskingOperation operation) {
        this.operation = operation;
    }

    public DataMaskingOperation operation() {
        return this.operation;
    }

}

public final class DataMaskingSerializer extends StdScalarSerializer<Object> {
    private final DataMaskingOperation operation;

    public DataMaskingSerializer() {
        super(String.class, false);
        this.operation = null;
    }

    public DataMaskingSerializer(DataMaskingOperation operation) {
        super(String.class, false);
        this.operation = operation;
    }


    public boolean isEmpty(SerializerProvider prov, Object value) {
        String str = (String)value;
        return str.isEmpty();
    }

    public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        if (Objects.isNull(operation)) {
            String content = DataMaskingFunc.ALL_MASK.operation().mask((String) value, null);
            gen.writeString(content);
        } else {
            String content = operation.mask((String) value, null);
            gen.writeString(content);
        }
    }

    public final void serializeWithType(Object value, JsonGenerator gen, SerializerProvider provider, TypeSerializer typeSer) throws IOException {
        this.serialize(value, gen, provider);
    }

    public JsonNode getSchema(SerializerProvider provider, Type typeHint) {
        return this.createSchemaNode("string", true);
    }

    public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint) throws JsonMappingException {
        this.visitStringFormat(visitor, typeHint);
    }
}

3. 自定义AnnotationIntrospector,适配我们自定义注解返回相应的Serializer  

@Slf4j
public class DataMaskingAnnotationIntrospector extends NopAnnotationIntrospector {

    @Override
    public Object findSerializer(Annotated am) {
        DataMasking annotation = am.getAnnotation(DataMasking.class);
        if (annotation != null) {
            return new DataMaskingSerializer(annotation.maskFunc().operation());
        }
        return null;
    }

}

4. 覆盖ObjectMapper


@Configuration(
        proxyBeanMethods = false
)
public class DataMaskConfiguration {

    @Configuration(
            proxyBeanMethods = false
    )
    @ConditionalOnClass({Jackson2ObjectMapperBuilder.class})
    static class JacksonObjectMapperConfiguration {
        JacksonObjectMapperConfiguration() {
        }

        @Bean
        @Primary
        ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
            ObjectMapper objectMapper = builder.createXmlMapper(false).build();
            AnnotationIntrospector ai = objectMapper.getSerializationConfig().getAnnotationIntrospector();
            AnnotationIntrospector newAi = AnnotationIntrospectorPair.pair(ai, new DataMaskingAnnotationIntrospector());
            objectMapper.setAnnotationIntrospector(newAi);
            return objectMapper;
        }
    }

}

5. 返回对象加上注解


public class User implements Serializable {
    /**
     * 主键ID
     */
    private Long id;

    /**
     * 姓名
     */
    @DataMasking(maskFunc = DataMaskingFunc.ALL_MASK)
    private String name;

    /**
     * 年龄
     */
    private Integer age;

    /**
     * 邮箱
     */
    @DataMasking(maskFunc = DataMaskingFunc.ALL_MASK)
    private String email;

}

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

一个注解搞定接口返回数据脱敏 的相关文章

  • STL常用容器——deque容器的使用

    文章目录 STL常用容器 deque容器的使用1 deque 容器简介2 deque容器的构造函数3 deque的赋值操作4 deque大小操作5 deque容器添加和删除元素6 deque容器访问元素7 容器内元素排序 STL常用容器 d
  • STL常用容器——stack容器的使用

    文章目录 STL常用容器 stack容器的使用1 stack容器介绍2 stack容器常用接口 STL常用容器 stack容器的使用 1 stack容器介绍 stack容器简介 stack容器是堆栈容器 xff0c 该容器具有先进后出的特性
  • STL常用容器——queue容器的使用

    文章目录 STL常用容器 queue容器的使用1 queue容器的介绍2 queue容器常用接口2 1 queue容器构造函数2 2 queue队列容器常用的成员函数 STL常用容器 queue容器的使用 1 queue容器的介绍 queu
  • STL常用容器—— list 容器的使用

    文章目录 STL常用容器 list 容器的使用1 list 容器介绍2 list容器的构造函数3 list容器的赋值和交换4 list容器大小操作5 list容器添加和删除元素操作6 list容器数据存取7 list容器反转和排序 STL常
  • STL常用容器——set容器的使用

    文章目录 STL常用容器 set容器的使用1 set容器简介2 set容器的构造和赋值3 set容器的大小和交换4 set容器的添加与删除5 set容器的查找与统计6 pair类模板7 set和multiset的区别8 set容器的排序 S
  • STL常用容器——map容器的使用

    文章目录 STL常用容器 map容器的使用1 map容器介绍2 map容器构造和赋值3 map容器大小和交换4 map容器的添加和删除4 1 insert插入数据的四种方式4 2 删除键值对 5 map容器查找和统计6 map容器排序 ST
  • STL常用算法——遍历算法

    文章目录 STL常用算法 遍历算法1 for each 2 transform STL常用算法 遍历算法 1 for each for each xff1a 遍历容器 xff0c 对容器中的每一个元素调用函数或函数对象 函数原型 xff1a
  • STL常用算法——查找算法

    文章目录 STL常用算法 查找算法1 find 2 find if 3 adjacent find 4 binary search 5 count 和count if 5 1 count 5 2 count if STL常用算法 查找算法
  • 视觉识别示例-海康威视

    视觉识别示例 海康威视 C Program Files x86 MVS Development Documentations1 在海康威视软件MVS xff0c 默认安装目录下有示例及说明 xff0c 如上图是示例说明 C Program
  • STL常用算法——排序算法

    文章目录 STL常用算法 排序算法1 sort 2 random shuffle 3 merge 4 reverse STL常用算法 排序算法 1 sort sort xff1a 对容器或普通数组中范围内的元素进行排序 xff0c 默认进行
  • STL常用算法——拷贝和替换算法

    文章目录 STL常用算法 拷贝和替换算法1 copy 2 replace 3 replace if 4 swap STL常用算法 拷贝和替换算法 1 copy copy 函数 xff1a 将源容器内指定范围的元素拷贝到目的容器中 函数原型
  • STL常用算法——算术生成算法和集合算法

    文章目录 STL常用算法 算术生成算法和集合算法1 算术生成算法1 1 accumulate 1 2 fill 和fill n 2 集合算法2 1 set intersection 2 2 set union 2 3 set differe
  • CompletableFuture的使用

    文章目录 1 Future2 CompletableFuture 并行 xff0c 并发 并发 xff1a 一个实体上 xff0c 多个任务有序执行 并行 xff1a 多个实体上 xff0c 多个任务同时执行 用户线程 用户线程是系统的工作
  • 将本地jar添加到Maven仓库

    一 将jar添加到本地仓库的做法 xff1a 以下面pom xml依赖的jar包为例 xff1a 实际项目中pom xml依赖写法 xff1a html view plain copy lt dependency gt lt groupId
  • nodejs如何实现Digest摘要认证?

    文章目录 1 前言2 原理3 过程4 node实现摘要认证5 前端如何Digest摘要登录认证 xff08 下面是海康的设备代码 xff09 1 前言 根据项目需求 xff0c 海康设备ISAPI协议需要摘要认证 xff0c 那么什么是摘要
  • HAL库中断方式进行串口通信

    目录 一 通过CubeMX配置项目 二 在keil配置代码 三 烧录运行 四 输出 五 总结 六 参考链接 一 通过CubeMX配置项目 二 在keil配置代码 main函数中的while循环里面添加传输代码 if flag 61 61 1
  • 串口UART

    目录 串口概念 串口rs232 数据格式 注意事项 总体结构图 代码verilog 接收模块 结构图 波形图 编辑 代码 verilog 发送模块 结构图 波形图 代码 verilog 串口rs485 串口概念 串口是异步 串行通信接口 x
  • vs code 无法打开任何文件/新建文件报错this.configurationService.getValue(…) || []).filter is not a function

    vs code 无法打开任何文件 新建文件报错this configurationService getValue filter is not a function 主要起因是在一台mac 电脑上登录了vs code的同步帐号 xff0c
  • ESP32环境搭建遇到的问题记录

    关于安信可AiThinkerIDE V1 0自带的esp idf xff08 v3 3 咨询淘宝上的技术 xff09 xff0c 是可以在该IDE上导入运行的 xff1b 但是我使用了最新的esp idf v4 2 xff0c 在IDE上却

随机推荐

  • SVN trunk(主线) branch(分支) tag(标记) 用法详解和详细操作步骤

    一 xff1a 使用场景 xff1a 假如你的项目 xff08 这里指的是手机客户端项目 xff09 的某个版本 xff08 例如1 0版本 xff09 已经完成开发 测试并已经上线了 xff0c 接下来接到新的需求 xff0c 新需求的开
  • 有关HTTP 401验证的那些事儿

    前段时间突然遇到有一个需求 xff1a 要求能够抓取到NVR上连接的摄像头设备列表 因为要的比较急 xff0c 而且我还没啃透海康SDK的文档 xff0c 所以只好考虑另辟蹊径 xff0c 用一些别的方法来达到目标咯 我们登录到NVR的we
  • LCD段码屏 真值表转换

    以lcd段码屏驱动芯片TM1621D为例子 typedef union struct uint8 t a 1 uint8 t b 1 uint8 t c 1 uint8 t d 1 uint8 t e 1 uint8 t f 1 uint8
  • 段码屏走线转换为真值表

    54117PIN1234567891011SEG1ABCDEG PM2EFG2ABCD3EFG COL3ABCD4EFG4ABCD1B 2A COL 3A 4A1ADEG 2BF 3BF 4BF1C 2CG 3CG 4CGPM 2DE 3D
  • 硬件电路,AD-DC电路中元器件的作用

    热敏电阻 xff1a 功率型NTC热敏电阻多用于电源抑制浪涌 1 在AC220V输入端串联热敏电阻 xff0c 在电路电源接通瞬间 xff0c 电路中会产生比正常工作时高出许多倍的浪涌电流 xff0c 而NTC热敏电阻器的初始阻值较大 xf
  • CentOS 7内核更换教程

    CentOS 7支持安装锐速的内核 xff1a 3 10 0 327 el7 x86 64 使用下面命令下载及更换内核 rpm ivh http xz wn789 com CentOSkernel kernel 3 10 0 229 1 2
  • 关于STM32 CAN 滤波器设置的记录

    滤波模式有以下两种 xff1a 屏蔽位模式 标识符列表模式 过滤器的位宽 xff1a 16位过滤器 32位过滤器 下面记录一下我做过测试的代码 代码说明 xff1a 这是CAN2的滤波器 xff0c stm32f107的两组CAN滤波器是共
  • 定时器判断串口接收结束

    void USART1 IRQHandler void 串口1中断服务程序 u8 Res if USART GetITStatus USART1 USART IT RXNE 61 RESET 接收中断 Res 61 USART Receiv
  • gcc编译时对'xxxx'未定义的引用问题

    这个主要的原因是gcc编译的时候 xff0c 各个文件依赖顺序的问题 在gcc编译的时候 xff0c 如果文件a依赖于文件b xff0c 那么编译的时候必须把a放前面 xff0c b放后面 例如 在main c中使用了temp xff0c
  • 【编译人生】跨平台程序设计BOOST库以及编译方案的选择

    boost库很方便 xff0c 不用说 xff0c 下面是编译方法 xff0c 以WINDOWS平台为例 1 在 boost解压缩文件路径下 xff08 可能不同版本的路径位置build有所不同 xff09 cd d tools build
  • CAN总线的标准帧和扩展帧

    CAN总线的标准帧和扩展帧主要决定帧ID的长度 xff0c 标准帧的帧ID长度是11位 xff0c 帧ID的范围是000 7FF 扩展帧的帧ID长度是29位 xff0c 帧ID的范围是0000 0000 1FFF FFFF CANopen帧
  • CAN扩展帧详解

    寻址方式
  • linux 发送get/post请求

    目录 get post 43 json get curl location request GET 39 http xxxx param1 61 2027xxxx 39 url参数中涉及特殊字符的参数部分 需要转义 例如 curl 34 h
  • ROS -PCL程序包建立和CMakelist.txt修改

    一 创建工作空间 wtj 64 wtj echo ROS PACKAGE PATH wtj 64 wtj mkdir p dev catkin ws src wtj 64 wtj cd dev catkin ws src wtj 64 wt
  • jetson nano 供电模式的切换或自定义供电模式

    前言 xff1a jetson nano 开发板在预设的10W MAXN 模式下需要用5v4A的DC供电 用5v2A的DC或者micro usb供电建议使用5W模式 供电不足会导致掉电关机 以下是学习jetson nano时 xff0c 对
  • 自动驾驶之——CAN总线简介

    自动驾驶技术之 无人驾驶中的CAN总线 CAN 是Controller AreaNetwork 的缩写 xff0c 中文名为控制器局域网络 xff0c 是ISO国际标准化的串行通信协议 xff0c 是一种用于实时应用的串行通讯协议总线 xf
  • CMake中find_package()查找指定版本的库,以Qt库多版本共存为例

    Qt安装了多个版本时 xff0c CMake中写的find package 到底找到的是哪个库 xff1f 例如 xff0c 我电脑安装了两个版本的Qt xff0c 一个是5 12 3另一个是5 14 2 此时我的CMake如何指定使用哪个
  • 游戏中常用的寻路算法(6):地图表示

    在本系列文档大部分内容中 xff0c 我都假设A 用于某种网格上 xff0c 其中的 节点 是一个个网格的位置 xff0c 边 是从某个网格位置出发的各个方向 然而 xff0c A 可用于任意图形 xff0c 不仅仅是网格 xff0c 有很
  • Redis 官方可视化工具

    RedisInsight 是一个直观高效的 Redis GUI 管理工具 xff0c 它可以对 Redis 的内存 连接数 命中率以及正常运行时间进行监控 xff0c 并且可以在界面上使用 CLI 和连接的 Redis 进行交互 xff08
  • 一个注解搞定接口返回数据脱敏

    下午惬意时光 xff0c 突然产品小姐姐走到我面前 xff0c 打断我短暂的摸鱼time xff0c 企图与我进行深入交流 xff0c 还好我早有防备没有闪 xff0c 打开瑞star的点单页面 xff0c 暗示没有一杯coffee解决不了