接口数据脱敏实现方案

背景

敏感信息如手机号、身份证、邮箱等信息需要脱敏后展示给前台,如果需要查看,则需要申请权限,查询时需要记录操作日志。

方案

通过JsonSerializer和注解,在json序列化的时候做脱敏操作

此处使用redis存储了加密后的key和明文,如果不需要反查和记录操作日志可以去掉相关代码

流程

代码

脱敏工具类

package com.sky.ddtcode.desensitization;


import cn.hutool.core.util.StrUtil;

/**
 * 脱敏工具类
 */
public class DesensitizedUtil
{
    /**
     * 密码的全部字符都用*代替,比如:******
     *
     * @param password 密码
     * @return 脱敏后的密码
     */
    public static String password(String password)
    {
        if (StrUtil.isBlank(password))
        {
            return StrUtil.EMPTY;
        }
        return StrUtil.repeat('*', password.length());
    }

    /**
     * 车牌中间用*代替,如果是错误的车牌,不处理
     *
     * @param carLicense 完整的车牌号
     * @return 脱敏后的车牌
     */
    public static String carLicense(String carLicense)
    {
        if (StrUtil.isBlank(carLicense))
        {
            return StrUtil.EMPTY;
        }
        // 普通车牌
        if (carLicense.length() == 7)
        {
            carLicense = StrUtil.hide(carLicense, 3, 6);
        }
        else if (carLicense.length() == 8)
        {
            // 新能源车牌
            carLicense = StrUtil.hide(carLicense, 3, 7);
        }
        return carLicense;
    }
}

脱敏策略枚举类

package com.sky.ddtcode.desensitization;

import java.util.function.Function;

/**
 * 脱敏策略,枚举类,针对不同的数据定制特定的策略
 */
public enum SensitiveStrategy
{
    /**
     * 姓名,第2位星号替换
     */
    USERNAME(s -> s.replaceAll("(\\S)\\S(\\S*)", "$1*$2")),

    /**
     * 密码,全部字符都用*代替
     */
    PASSWORD(DesensitizedUtil::password),

    /**
     * 身份证,中间10位星号替换
     */
    ID_CARD(s -> s.replaceAll("(\\d{4})\\d{10}(\\d{4})", "$1** **** ****$2")),

    /**
     * 手机号,中间4位星号替换
     */
    PHONE(s -> s.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")),

    /**
     * 电子邮箱,仅显示第一个字母和@后面的地址显示,其他星号替换
     */
    EMAIL(s -> s.replaceAll("(^.)[^@]*(@.*$)", "$1****$2")),

    /**
     * 银行卡号,保留最后4位,其他星号替换
     */
    BANK_CARD(s -> s.replaceAll("\\d{15}(\\d{3})", "**** **** **** **** $1")),

    /**
     * 车牌号码,包含普通车辆、新能源车辆
     */
    CAR_LICENSE(DesensitizedUtil::carLicense);

    private final Function<String, String> desensitizer;

    SensitiveStrategy(Function<String, String> desensitizer)
    {
        this.desensitizer = desensitizer;
    }

    public Function<String, String> desensitizer()
    {
        return desensitizer;
    }
}

脱敏注解

package com.sky.ddtcode.desensitization;

import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside
@JsonSerialize(using = SensitiveJsonSerializer.class)
public @interface Sensitive {
    //脱敏策略
    SensitiveStrategy strategy();
}

序列化注解自定义实现

此处的加密数据明文存储在redis里面,查询的时候根据rediskey获取数据,并记录操作日志。

此处是为了统一所以采用此种方式,也可以针对单个信息直接接口查询记录操作日志,但是接口会比较多

package com.sky.ddtcode.desensitization;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.IOException;
import java.util.Objects;
import java.util.UUID;

/**
 * 序列化注解自定义实现
 * JsonSerializer<String>:指定String 类型,serialize()方法用于将修改后的数据载入
 */
public class SensitiveJsonSerializer extends JsonSerializer<String> implements ContextualSerializer {

    @Autowired
    RedisService redisService;
    private SensitiveStrategy strategy;

    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        String newValue = strategy.desensitizer().apply(value);
        String guid=UUID.randomUUID().toString();
        String sensitiveValue=newValue+"_"+guid;
        redisService.save(guid,value);
        gen.writeString(sensitiveValue);
        //如果不需要反查明文信息,则可以去掉redisService直接使用下面的代码
        //gen.writeString(strategy.desensitizer().apply(value));
    }

    /**
     * 获取属性上的注解属性
     */
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
        Sensitive annotation = property.getAnnotation(Sensitive.class);
        if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass())) {
            this.strategy = annotation.strategy();
            return this;
        }
        return prov.findValueSerializer(property.getType(), property);
    }
}

测试实体类

@Data
public class Person {
    /**
     * 真实姓名
     */
    @Sensitive(strategy = SensitiveStrategy.USERNAME)
    private String realName;
    /**
     * 电话号码
     */
    @Sensitive(strategy = SensitiveStrategy.PHONE)
    private String phoneNumber;
    /**
     * 身份证号码
     */
    @Sensitive(strategy = SensitiveStrategy.ID_CARD)
    private String idCard;
}

测试类 

package com.sky.ddtcode.controller;

import com.sky.ddtcode.desensitization.Person;
import com.sky.ddtcode.desensitization.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/sensitive")
public class SensitiveController {
    @Autowired
    RedisService redisService;
    @GetMapping("/test")
    public Person test(){
        Person user = new Person();
        user.setRealName("skywhite");
        user.setPhoneNumber("1888888888");
        user.setIdCard("411101199901013344");
        return user;
    }
    //如果不需要反查明文则可以不要这个接口和redisService服务
    @GetMapping("/realValue")
    public String realValue(String guid){
       String value= redisService.getValue(guid);
       //todo  记录操作日志,操作人信息,数据类型信息之类的
        return value;
    }
}

测试

数据加密

明文查询

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/606950.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

查看pytorch与cuda对应版本

查看cuda版本 打开cmd,输入nvidia-smi&#xff0c;即可可以看到cuda的版本了 2. pytorch与cuda版本对应关系 可以参考这篇文章&#xff0c;写的非常详细&#xff1a;https://blog.csdn.net/FL1768317420/article/details/134769203

预测市场?预测股票?如何让预测有更高的准确率?

我们发现在足球赛中&#xff0c;只要知道一个简单的讯息&#xff08;主队过去的获胜机率超过一半&#xff09;&#xff0c;预测力就会明显好过随便乱猜。如果再加上第二个简单的讯息&#xff08;胜负纪录较佳的队伍会略占优势&#xff09;&#xff0c;可以再进一步提升预测力。…

遇事不决,阿尔萨斯(Arthas)

文章目录 一、cat log.log | grep 流水号 引发的惨案二、Collections.sort排序long型强转int型引发的惨案 一、cat log.log | grep 流水号 引发的惨案 接口报错&#xff0c;查看日志是空指针&#xff0c;但是没有详细的报错信息。 以为是日志打印格式的问题&#xff0c;遂改变…

2024年软件测试最新Web安全测试(文末送电子书)_电子书下载 安全测试,腾讯软件测试开发面试经验

网上学习资料一大堆&#xff0c;但如果学到的知识不成体系&#xff0c;遇到问题时只是浅尝辄止&#xff0c;不再深入研究&#xff0c;那么很难做到真正的技术提升。 需要这份系统化的资料的朋友&#xff0c;可以戳这里获取 一个人可以走的很快&#xff0c;但一群人才能走的更…

Spring AI实战之一:快速体验(OpenAI)

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码)&#xff1a;https://github.com/zq2599/blog_demos 关于Spring AI Spring Boot、Spring Cloud、Spring Data&#xff0c;作为一名Java程序员&#xff0c;相信您对这些概览早已耳熟能详&#xff0c;或者天天在用…

本地搭建springboot服务并实现公网远程调试本地接口

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

重发被恶意举报的主食冻干测评,速看可能再被删!PR、希喂和SC真实对比PK!

要给猫咪提供高品质主食&#xff0c;主食冻干是不二之选。主食冻干不仅含肉量高、吸收消化率高&#xff0c;还有着丰富的、普通猫粮无法提供的各类营养素&#xff0c;满足猫咪微量元素的需求。可以说是营养与生骨肉喂养媲美&#xff0c;又能完美避开生骨肉细菌超标带来的一系列…

KaiwuDB 解析器之语义解析

KaiwuDB 解析器介绍 解析器是数据库系统的重要组成部分之一&#xff0c;主要的功能是将客户端输入的 SQL 语句分解为语法单元&#xff0c;然后将这些语法单元转化成数据库内部可识别的数据结构&#xff0c;最终生成数据库可以执行的计划。 KaiwuDB 的一条 SQL 执行的整个生命…

go导入包时提示no required module provides package解决方法

原因&#xff0c;这个包在你的本机没有安装 如redis包的提示为 could not import github.com/gomodule/redigo/redis (no required module provides package "github.com/gomodule/redigo/redis")解决方法&#xff1a; go get github.com/gomodule/redigo/redis

PHP+MySQL组合开发 自定义商城系统源码 带完整的安装代码包以及安装部署教程

随着电子商务的蓬勃发展&#xff0c;越来越多的企业和个人希望拥有自己的在线商城系统。小编给大家分享一款基于PHP和MySQL技术栈&#xff0c;开发的一套自定义商城系统源码。该系统旨在帮助用户快速搭建稳定、高效的电子商务平台&#xff0c;并提供灵活的自定义功能&#xff0…

日本站群服务器的优点以及适合该服务器的业务类型?

日本站群服务器的优点以及适合该服务器的业务类型? 日本站群服务器是指位于日本地区的多个网站共享同一台服务器的架构。这种服务器架构有着诸多优点&#xff0c;使其成为许多企业和网站管理员的首选。以下是日本站群服务器的优点以及适合该服务器的业务类型的分析&#xff1…

链表经典面试题02--链表的带环问题

目录 引言 环形链表 题目描述: 思路分析: 代码展示: 面试中遇到的问题: 环形链表Ⅱ 题目描述: 思路分析: 代码展示: 面试中遇到的问题: 方法二: 随机链表的复制 题目描述: 思路分析: 代码展示: 小结 引言 这个专题专门讲解链表的带环问题,并且对面试有关链表带环…

开源文档管理系统Paperless-ngx如何在Linux系统运行并发布至公网

文章目录 1. 部署Paperless-ngx2. 本地访问Paperless-ngx3. Linux安装Cpolar4. 配置公网地址5. 远程访问6. 固定Cpolar公网地址7. 固定地址访问 Paperless-ngx是一个开源的文档管理系统&#xff0c;可以将物理文档转换成可搜索的在线档案&#xff0c;从而减少纸张的使用。它内置…

使用HashMap实现,对一个字符集进行哈夫曼编码

最终达到的效果: 调用一个类 class HuffmanCodin{.....} 使用类中的静态方法&#xff0c;获取哈夫曼编码&#xff1a; 事前准备——哈夫曼树的节点定义 class Node implements Comparable<Node> {int weight;//权重Node left;Node right;char ch;//关键字&#xff0c…

asp.net论坛指南系统

说明文档 运行前附加数据库.mdf&#xff08;或sql生成数据库&#xff09; 主要技术&#xff1a; 基于asp.net架构和sql server数据库 登陆可查看 浏览记录 TA的发布 TA的回复 TA的收藏 TA的点赞 管理员登陆可以查看举报管理 编辑管理 认证审核 帖子置顶申请审核 运行环境…

如何利用IPIDEA代理IP优化数据采集效率?

一、 前言二、 IPIDEA介绍三、体验步骤四、实战训练五、结语 一、 前言 在全球化与信息化交织的当代社会&#xff0c;数据已成为驱动商业智慧与技术革新的核心引擎。网络&#xff0c;作为信息汇聚与交流的枢纽&#xff0c;不仅是人们获取知识的窗口&#xff0c;更是商业活动与技…

FX110书籍推荐:如何快速成为一名专业股票投资人?

股票投资领域有一本神作《股票交易入门》&#xff0c;它是股票从业人员的入门必备书籍。 关于股票入门的书籍很多&#xff0c;但这本书涉及的知识面最全、实用性最强。从这本书里&#xff0c;我们可以领略到股票交易世界的跌宕起伏而又波澜壮阔的魅力。本书作者 本书的作者是美…

Navicat导入sql报错[Err] 1046 - No database selected

Navicat导入sql报错[Err] 1046 - No database selected ​ 今天系统重装了&#xff0c;就很完蛋。所有东西都重新下载安装。向Navicat导入sql的时候导入失败&#xff1a; 报错[Err] 1046 - No database selected。我很疑惑地又导了几次。当然又全都失败. 错误造成原因&#x…

项目风采展示【车酷-雷克萨斯2】

1&#xff1a;支持桌面展示 2&#xff1a;支持桌面时钟 3&#xff1a;支持桌面陀螺仪

怎么将文字做成二维码?文本活码在线的生成技巧

文本类型的活码该如何来制作呢&#xff1f;通过二维码来展示文字信息是现在很常用的一种方式&#xff0c;包括物品、建筑、人员等方面的信息&#xff0c;都可以用生成二维码后让其他人通过扫码了解自己需要的信息。那么文本活码的制作需要几步操作呢&#xff1f;下面就教大家使…