记录一种数据屏蔽方式

项目需求是根据不同的脱敏规则对敏感数据进行屏蔽,如身份证号、手机号等。为避免代码冗余和提高可维护性,采用了创建MaskingFunction、MaskingConfig和MaskingUtil类的方式。MaskingFunction实现屏蔽规则,MaskingConfig配置字段规则,MaskingUtil根据配置动态处理数据。测试表明,该方案有效执行了敏感数据屏蔽。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

项目中有一个需求,需要将列表中敏感数据做屏蔽,屏蔽数据根据字段数据的不同,也有对应的屏蔽规则。例如:身份证号、手机号、电话、地址等。大致需求就是这样,即根据脱敏规则,对敏感数据做脱敏屏蔽处理。

项目中有很多列表页面,对应的数据库表字段名称也都不一样,如果使用if else 方式去实现,对每个列表接口数据做判断,性能暂且不说,势必会造成代码冗余,使代码阅读性降低,更改起来非常麻烦。

这里想一个思路,

1、先在写一个屏蔽规则方法类(这里命名为MaskingFunction)类中使用java静态方法,实现每种数据的屏蔽规则。

2、然后再写一个配置类(MaskingConfig),将实体类对应的有屏蔽要求的字段的屏蔽规则,配置保存到Map中。

3、最后写一个工具类,这个类传入两个参数,一个是实体类名称(tabName)、一个是要屏蔽的数据(List<Map>)。根据实体类名称可以从配置类中查询到字段的屏蔽规则,然后再循环操作对数据做处理。

代码如下:

MaskingFunction类。实现每种屏蔽规则

package com.ruoyi.masking;


import org.apache.commons.lang3.StringUtils;

/**
 * 敏感数据屏蔽规则的实现方法类
 */
public class MaskingFunction {

    public static final String replace = "******";
    public static final String replace2 = "*";

    /**
     * 身份证号屏蔽规则实现方法
     * 保存前六位,和末尾两位,中间用星号替换
     * @param idCard 身份证号
     * @return 加工后返回的数据
     */
    public static String idCardF(String idCard){
        if(StringUtils.isBlank(idCard)){
            return idCard;
        }
        int length = idCard.length();
        if(length <= 8){
            return idCard;
        }
        return idCard.substring(0,6) + replace + idCard.substring(length-2);
    }

    /**
     * 手机号屏蔽规则实现方法
     * 保存前三位和后四位,中间四位用星号替换
     * @param phone
     * @return
     */
    public static String phoneF(String phone){
        if(StringUtils.isBlank(phone)){
            return phone;
        }
        int length = phone.length();
        if(length <= 7){
            return phone;
        }
        return phone.substring(0,3) + "****" + phone.substring(length-4);
    }

}

MaskingConfig类。配置每个实体类字段的屏蔽规则实现方法

package com.ruoyi.masking;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

/**
 * 敏感数据脱敏屏蔽规则配置类
 */
public class MaskingConfig {

    private final static Logger log = LoggerFactory.getLogger(MaskingConfig.class);

    //保存敏感数据的配置。key是要屏蔽数据的实体类名称,value的map保存每个字段对应的屏蔽方法
    public static Map<String,Map<String, Function<String,String>>> mc = new HashMap<>();

    //使用静态代码块,将敏感数据屏蔽规则加载到mc中
    static {
        log.info("----屏蔽规则配置初始化");
        //TestTab实体类屏蔽规则配置
        mc.put("TestTab",new HashMap<String, Function<String,String>>(){{
            //身份证号字段
            put("idCard",MaskingFunction::idCardF);
            //电话号字段
            put("phone",MaskingFunction::phoneF);
        }});
        //TestTable实体类屏蔽规则配置
        mc.put("TestTable",new HashMap<String, Function<String,String>>(){{
            //地址
//            put("address",MaskingFunction::address);
            //电话号字段
            put("phone",MaskingFunction::phoneF);
        }});

    }

}

MaskingUtil类。提供一个静态方法,根据配置完成对数据中敏感数据的屏蔽

package com.ruoyi.masking;

import com.ruoyi.common.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;

/**
 * 敏感数据屏蔽工具类
 *
 */
public class MaskingUtil {

    private static Logger log = LoggerFactory.getLogger(MaskingUtil.class);

    /**
     * 敏感数据屏蔽方法。
     * @param entityName 要屏蔽数据的实体类名称
     * @param list 数据集合
     * @return 屏蔽完成的数据
     */
    public static List<Map<String,Object>> masking(String entityName,List<Map<String,Object>> list){

        if (StringUtils.isBlank(entityName)){
            log.error("-----请传入entityName参数");
            return list;
        }
        if(list==null || list.isEmpty()){
            return list;
        }
        //获取实体类entityName,配置的屏蔽方法
        Map<String, Function<String,String>> maskingConfig = MaskingConfig.mc.get(entityName);
        if(maskingConfig == null || maskingConfig.size() == 0){
            return list;
        }

        list.forEach(data -> mas(maskingConfig,data));


        return list;
    }

    private static void mas(Map<String, Function<String,String>> maskingConfig, Map<String,Object> data){

        if(data == null || data.size() == 0){
            return;
        }

        //获取配置类中字段名称
        Set<String> keySet = maskingConfig.keySet();

        for (String key : keySet) {

            Object value = data.get(key);
            if(value == null){
                continue;
            }
            String str = value.toString();
            if(StringUtils.isBlank(str)){
                continue;
            }
            Function<String,String> maskingFunction = maskingConfig.get(key);
            if (maskingFunction == null){
                log.error("-----字段key={},配置的屏蔽方法为空",key);
                continue;
            }
            //执行屏蔽方法,替换data中的数据
            data.put(key,maskingFunction.apply(str));

        }

    }

}

测试类MaskingTest

package com.ruoyi.masking;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import org.apache.poi.ss.formula.functions.T;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 测试屏蔽方法
 */
public class MaskingTest {

    public static void main(String[] args) {
        MaskingTest mt = new MaskingTest();
        List<TestTab> testTabs = mt.queryTestTab(null);
        new JSONObject();
        String str = JSON.toJSONString(testTabs);
        List<Map<String, Object>> maps = JSON.parseArray(str, (Type) Map.class);
//        JSON.parse("sddddd")
//        List<Map<String,Object>> list = testTabs.stream().map(t -> n)
        System.out.println("屏蔽前");
        System.out.println(maps);
        MaskingUtil.masking("TestTab",maps);
        System.out.println("屏蔽后");
        System.out.println(maps);
    }

    /**
     * 这里写一个模拟方法,返回数据。模拟从数据库读取数据
     * @param testTab
     * @return
     */
    public  List<TestTab> queryTestTab(TestTab testTab){
        List<TestTab> list = new ArrayList<>();
        list.add(new TestTab("1","1305291195010101234","15012345678","张三","张三简介"));
        list.add(new TestTab("2","1305291195010105566","15012345","李四","李四简介"));
        list.add(new TestTab("3","1305291195010101111","1502345","赵六","赵六简介"));
        return list;
    }

    class TestTab {
        private String id;
        private String idCard;
        private String phone;
        private String name;
        private String desc;

        public TestTab() {
        }

        public TestTab(String id, String idCard, String phone, String name, String desc) {
            this.id = id;
            this.idCard = idCard;
            this.phone = phone;
            this.name = name;
            this.desc = desc;
        }

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getIdCard() {
            return idCard;
        }

        public void setIdCard(String idCard) {
            this.idCard = idCard;
        }

        public String getPhone() {
            return phone;
        }

        public void setPhone(String phone) {
            this.phone = phone;
        }

        public String getName() {
            return name;
        }

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

        public String getDesc() {
            return desc;
        }

        public void setDesc(String desc) {
            this.desc = desc;
        }
    }

}

打印的日志

屏蔽前
[{phone=15012345678, idCard=1305291195010101234, name=张三, id=1, desc=张三简介}, {phone=15012345, idCard=1305291195010105566, name=李四, id=2, desc=李四简介}, {phone=1502345, idCard=1305291195010101111, name=赵六, id=3, desc=赵六简介}]
23:16:57.468 [main] INFO  c.r.m.MaskingConfig - [<clinit>,22] - ----屏蔽规则配置初始化
屏蔽后
[{phone=150****5678, idCard=130529******34, name=张三, id=1, desc=张三简介}, {phone=150****2345, idCard=130529******66, name=李四, id=2, desc=李四简介}, {phone=1502345, idCard=130529******11, name=赵六, id=3, desc=赵六简介}]

从日志中看,TestTab这个实体类数据都按照我们配置的方法,执行了敏感数据屏蔽。

实际使用中,如果有其他的敏感数据屏蔽规则,可按照以下操作:

1、以在MaskingFunction这个类中按照规则实现的屏蔽方法。

2、在MackingConfig类中,配置好要屏蔽的实体类名称以及他的字段对应的屏蔽方法(可以参考TestTab的配置)。

3、查询出数据以后,调用MaskingUtil中的masking方法(参考测试类中的调用方式)。

这样就完成了敏感数据屏蔽。

现行的应该有成熟的框架,类似做数据校验这样,在实体类中加注解即可。由于时间等原因未去做相关的调查研究,如果有同行了解这些方面技术还望不吝指教。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值