SpringBoot进阶教程(七十五)数据脱敏

springboot,进阶,教程,七十五,数据,脱敏 · 浏览次数 : 929

小编点评

## 数据脱敏方式分析 本文介绍了使用注解的方式进行数据脱敏的两种方法: **1. DB层面的脱敏** * 使用 `SensitivityEnum` 枚举定义敏感字段的脱敏策略。 * 在每个 controller 中,根据脱敏策略,使用 `desensitizer()` 方法将敏感数据转换为不可见格式。 **2. 接口层面的脱敏** * 使用 `@Sensitivity` 注解声明接口层面的脱敏策略。 * 在每个接口方法中,使用 `desensitizer()` 方法进行数据脱敏。 **优点和缺点** **1. DB层面的脱敏** * 更易于实现,代码简洁。 * 可以使用现有的数据库函数进行脱敏。 **2. 接口层面的脱敏** * 更灵活,可以根据需求自由定制脱敏策略。 * 允许在逻辑层进行脱敏处理。 **推荐** 建议使用接口层面的脱敏方式,因为其更灵活性和可定制性。可以使用 `@Sensitivity` 注解定义不同的脱敏策略,根据业务需求进行切换。

正文

无论对于什么业务来说,用户数据信息的安全性无疑都是非常重要的。尤其是在数字经济大火背景下,数据的安全性就显得更加重要。数据脱敏可以分为两个部分,一个是DB层面,防止DB数据泄露,暴露用户信息;一个是接口层面,有些UI展示需要数据脱敏,防止用户信息被人刷走了。

v需求背景

DB层面的脱敏今天先不讲,今天先讲讲依赖于注解的接口层面的数据脱敏,接口层面的脱敏可能最原始和简单的方法就是在每个controller输出数据时,硬性处理。但是这么做的方案,如果后续脱敏规则改了,那需要改的地方就太多了,而且很容易有遗漏的地方,造成全站脱敏规则不统一的情况。所以我们建议的是用注解的方式,可插拔性更好,随时可以更改规则,更加的灵活。

我们今天接到的需求是这样的:

页面或者接口层面的脱敏,大多也是围绕用户手机号啊、真实姓名或者地址等等展开的。

v架构设计

2.1 脱敏字段枚举:SensitivityEnum

这里定义一个敏感字段的枚举,并设定各个字段的脱敏策略。

/**
 * @Author tou tou
 * @Date 2023/1/15
 * @Des 脱敏类型及策略,不同的字段类型适配不同的策略
 */
public enum SensitivityEnum {
    /**
     * 用户名
     */
    USERNAME(s -> s.replaceAll("\\S*(\\S)", "***$1")),
    /**
     * 身份证
     */
    ID_CARD(s -> s.replaceAll("(\\d{4})\\d{10}(\\w{4})", "$1****$2")),
    /**
     * 手机号
     */
    PHONE(s -> s.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")),
    /**
     * 地址
     */
    ADDRESS(s -> s.replaceAll("(\\S{3})\\S{2}(\\S*)\\S{2}", "$1****$2****"));


    private final Function<String, String> desensitizer;

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

    public Function<String, String> desensitizer() {
        return desensitizer;
    }
}
2.2 创建自定义隐私注解:Sensitivity

都说了,我们使用的是注解的方式脱敏,所以是需要声明一个脱敏注解的,需要用到的地方,按需声明注解即可。非常方便。

/**
 * @Author tou tou
 * @Date 2023/1/15
 * @Des
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside
@JsonSerialize(using = SensitivitySerializer.class)
public @interface Sensitivity {
    SensitivityEnum strategy();
}
2.3 创建序列化类:SensitivitySerializer
/**
 * @Author tou tou
 * @Date 2023/1/15
 * @Des
 */
public class SensitivitySerializer extends JsonSerializer<String> implements ContextualSerializer {
    private SensitivityEnum sensitivityEnum;

    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeString(sensitivityEnum.desensitizer().apply(value));
    }

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {

        Sensitivity annotation = property.getAnnotation(Sensitivity.class);
        if (Objects.nonNull(annotation)&&Objects.equals(String.class, property.getType().getRawClass())) {
            this.sensitivityEnum = annotation.strategy();
            return this;
        }

        return prov.findValueSerializer(property.getType(), property);
    }
}
2.4 使用了@Sensitivity注解的实体类
public class UserAccountVO {
    private Integer id;

    @Sensitivity(strategy = SensitivityEnum.USERNAME)
    private String username;

    private Integer age;

    @Sensitivity(strategy = SensitivityEnum.PHONE)
    private String tel;

    private String email;

    private String account;
}
2.5 插入mysql测试数据
create table useraccount
(
id INT(11),
username NVARCHAR(25),
age INT(11),
phone bigint,
email VARCHAR(80),
account VARCHAR(20),
pwd VARCHAR(20)
);

select * from useraccount;
insert into useraccount values(1,'张老三', 22, 13555551111,'13555551111@126.com','z13555551111', '13555551111');
2.6 测试接口
/**
 * @author toutou
 * @date by 2019/07
 */
@RestController
public class UserController {

    @Autowired
    UserAccountService userAccountService;
    
    @GetMapping("/user/getuser")
    public Result getUserAccountById(@RequestParam("uid") int id){
        UserAccountVO user = userAccountService.getUserAccountById(id);
        if(user != null){
            return Result.setSuccessResult(user);
        }else{
            return Result.setErrorResult(404, "用户不存在");
        }
    }
}

v运行效果

SpringBoot进阶教程(七十五)数据脱敏

v源码地址

https://github.com/toutouge/javademosecond/tree/master/hellolearn


作  者:请叫我头头哥
出  处:http://www.cnblogs.com/toutou/
关于作者:专注于基础平台的项目开发。如有问题或建议,请多多赐教!
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是作者坚持原创和持续写作的最大动力!

与SpringBoot进阶教程(七十五)数据脱敏相似的内容:

SpringBoot进阶教程(七十五)数据脱敏

无论对于什么业务来说,用户数据信息的安全性无疑都是非常重要的。尤其是在数字经济大火背景下,数据的安全性就显得更加重要。数据脱敏可以分为两个部分,一个是DB层面,防止DB数据泄露,暴露用户信息;一个是接口层面,有些UI展示需要数据脱敏,防止用户信息被人刷走了。 v需求背景 DB层面的脱敏今天先不讲,今

SpringBoot进阶教程(七十六)多维度排序查询

在项目中经常能遇到,需要对某些数据集合进行多维度排序的需求。对于集合多条件排序解决方案也有很多,今天我们就介绍一种,思路大致是设置一个分值的集合,这个分值是按照需求来设定大小的,再根据分值的大小对集合排序。 v需求背景 我们来模拟一个需求,现在需要查询一个用户列表,该列表需要实现的排序优先级如下:

SpringBoot进阶教程(七十七)WebSocket

WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

简单进行Springboot Beans归属模块单元的统计分析方法

简单进行Springboot Beans归属模块单元的统计分析方法 背景 基于Springboot的产品变的复杂之后 启动速度会越来越慢. 公司同事得出一个结论. beans 数量过多会导致启动速度逐渐变慢. 之前同事写过功能进行分析. 但是本着能不影响产品就不影响产品. 我想通过其他方式进行处理.

Springboot下micrometer+prometheus+grafana进行JVM监控的操作过程

Springboot下micrometer+prometheus+grafana进行JVM监控的操作过程 背景 同事今天提交了一个补丁. 给基于Springboot的产品增加了micrometer等收集jvm信息的工具 但是这边springboot的版本比较高,导致有异常. 启动直接失败了. 晚上九

Springboot简单功能示例-4 自定义加密进行登录验证

博主尝试通过gitee的发行版,使用Springboot为基础框架,逐步整合JWT、JPA、VUE等常用功能项目。【本节完成】使用bcprov-jdk18on的sm2加密算法对用户密码进行签名及认证

Springboot简单功能示例-5 使用JWT进行授权认证

博主尝试通过gitee的发行版,使用Springboot为基础框架,逐步整合JWT、JPA、VUE等常用功能项目。【本节完成】使用JWT规范完成登录、确权、登出等操作,分别对html请求和json请求进行处理

SpringBoot中单元测试如何对包含AopContext.currentProxy()的方法进行测试

今天在工作中遇到一个问题,一个Service类中有一个方法,其中使用了 AopContext.currentProxy() 去访问自身的函数,例如 int result = ((OrderServiceImpl) AopContext.currentProxy()).save(); 单元测试方法如下

一文读懂Apollo客户端配置加载流程

SpringBoot集成Apollo源码分析 本文基于 apollo-client 2.1.0 版本源码进行分析 Apollo 是携程开源的配置中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性。 Apollo支持4个维度管理Key-

SpringBoot 过滤器更改 Request body ,并实现数据解密

客户端、服务端网络通信,为了安全,会对报文数据进行加解密操作。 在SpringBoot项目中,最好使用参考AOP思想,加解密与Controller业务逻辑解耦,互不影响。 以解密为例:需要在request请求到达Controller之前进行拦截,获取请求body中的密文并对其进行解密,然后把解密后的