数据脱敏 (Jackson + Hutool 工具包)

一、简介

系统使用 Jackson 序列化策略对标注了 Sensitive 注解的属性进行脱敏处理

基于Hutool 脱敏案列: 

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside// 表示只对有此注解的字段进行序列化
@JsonSerialize(using = SensitiveJsonSerializer.class)// 指定序列化器
public @interface Sensitive {
    SensitiveStrategy strategy();
}

我们以身份证号码为例:

// 5***************1X
DesensitizedUtil.idCardNum("51343620000320711X", 1, 2);

对于约定俗成的脱敏,我们可以不用指定隐藏位数,比如手机号:

// 180****1999
DesensitizedUtil.mobilePhone("18049531999");

当然还有一些简单粗暴的脱敏,比如密码,只保留了位数信息:

// **********
DesensitizedUtil.password("1234567890");

 二、若依框架脱敏流程

2.1 注解类

@JacksonAnnotationsInside// 表示只对有此注解的字段进行序列化
@JsonSerialize(using = SensitiveJsonSerializer.class)// 指定序列化器

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside// 表示只对有此注解的字段进行序列化
@JsonSerialize(using = SensitiveJsonSerializer.class)// 指定序列化器
public @interface Sensitive {
    SensitiveStrategy strategy();
}

2.2  脱了策略枚举类

@AllArgsConstructor
public enum SensitiveStrategy {

    /**
     * 身份证脱敏
     */
    ID_CARD(s -> DesensitizedUtil.idCardNum(s, 3, 4)),

    /**
     * 手机号脱敏
     */ PHONE(DesensitizedUtil::mobilePhone),


    /**
     * 地址脱敏
     */
    ADDRESS(s -> DesensitizedUtil.address(s, 8)),

    /**
     * 邮箱脱敏
     */
    EMAIL(DesensitizedUtil::email),

    /**
     * 银行卡
     */
    BANK_CARD(DesensitizedUtil::bankCard);

    //可自行添加其他脱敏策略

    private final Function<String, String> desensitizer;

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

 使用的是HuTool包中的 DesensitizedUtil 类进行脱敏

/**
	 * 脱敏,使用默认的脱敏策略
	 * <pre>
	 * DesensitizedUtil.desensitized("100", DesensitizedUtil.DesensitizedType.USER_ID)) =  "0"
	 * DesensitizedUtil.desensitized("段正淳", DesensitizedUtil.DesensitizedType.CHINESE_NAME)) = "段**"
	 * DesensitizedUtil.desensitized("51343620000320711X", DesensitizedUtil.DesensitizedType.ID_CARD)) = "5***************1X"
	 * DesensitizedUtil.desensitized("09157518479", DesensitizedUtil.DesensitizedType.FIXED_PHONE)) = "0915*****79"
	 * DesensitizedUtil.desensitized("18049531999", DesensitizedUtil.DesensitizedType.MOBILE_PHONE)) = "180****1999"
	 * DesensitizedUtil.desensitized("北京市海淀区马连洼街道289号", DesensitizedUtil.DesensitizedType.ADDRESS)) = "北京市海淀区马********"
	 * DesensitizedUtil.desensitized("duandazhi-jack@gmail.com.cn", DesensitizedUtil.DesensitizedType.EMAIL)) = "d*************@gmail.com.cn"
	 * DesensitizedUtil.desensitized("1234567890", DesensitizedUtil.DesensitizedType.PASSWORD)) = "**********"
	 * DesensitizedUtil.desensitized("苏D40000", DesensitizedUtil.DesensitizedType.CAR_LICENSE)) = "苏D4***0"
	 * DesensitizedUtil.desensitized("11011111222233333256", DesensitizedUtil.DesensitizedType.BANK_CARD)) = "1101 **** **** **** 3256"
	 * DesensitizedUtil.desensitized("192.168.1.1", DesensitizedUtil.DesensitizedType.IPV4)) = "192.*.*.*"
	 * </pre>
	 *
	 * @param str              字符串
	 * @param desensitizedType 脱敏类型;可以脱敏:用户id、中文名、身份证号、座机号、手机号、地址、电子邮件、密码
	 * @return 脱敏之后的字符串
	 * @author dazer and neusoft and qiaomu
	 * @since 5.6.2
	 */

 2.3 数据脱敏的序列化工具

  • 重写序列化接口,调用具体序列化策略
  • 重写创建上写文方法,指定当前处理的策略
@Slf4j
public class SensitiveJsonSerializer extends JsonSerializer<String> implements ContextualSerializer {

    private SensitiveStrategy strategy;

    /**
     * <简述> 重写序列化方法
     * <详细描述>
     * @author syf
     * @date 2024/9/14 17:01
     * @param value
     * @param gen
     * @param serializers
     */
    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        try {
            // 获取注解
            SensitiveService sensitiveService = SpringUtils.getBean(SensitiveService.class);
            // 判断是否开启脱敏
            if (ObjectUtil.isNotNull(sensitiveService) && sensitiveService.isSensitive()) {
                // 调用策略 strategy.desensitizer().apply(value), gen.writeString写入值
                gen.writeString(strategy.desensitizer().apply(value));
            } else {
                gen.writeString(value);
            }
        } catch (BeansException e) {
            log.error("脱敏实现不存在, 采用默认处理 => {}", e.getMessage());
            gen.writeString(value);
        }
    }

    /**
     * <简述>重写创建上下文方法
     * <详细描述>
     * @author syf
     * @date 2024/9/14 16:54
     * @param prov
     * @param property
     * @return com.fasterxml.jackson.databind.JsonSerializer<?>
     */
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
        // 获取注解
        Sensitive annotation = property.getAnnotation(Sensitive.class);
        //注解不为空 并且 类型为String
        if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass())) {
            // 设置当前注解的策略为注解里面策略
            this.strategy = annotation.strategy();
            return this;
        }
        // 返回默认序列化器
        return prov.findValueSerializer(property.getType(), property);
    }
}
 注意:
 默认管理员不过滤
 需自行根据业务重写实现
public interface SensitiveService {

    /**
     * 是否脱敏
     */
    boolean isSensitive();

}

 三、测试案例

@RestController
@RequestMapping("/demo/sensitive")
public class TestSensitiveController extends BaseController {

    /**
     * 测试数据脱敏
     */
    @GetMapping("/test")
    public R<TestSensitive> test() {
        TestSensitive testSensitive = new TestSensitive();
        testSensitive.setIdCard("210397198608215431");
        testSensitive.setPhone("17640125371");
        testSensitive.setAddress("北京市朝阳区某某四合院1203室");
        testSensitive.setEmail("17640125371@163.com");
        testSensitive.setBankCard("6226456952351452853");
        return R.ok(testSensitive);
    }

    @Data
    static class TestSensitive {

        /**
         * 身份证
         */
        @Sensitive(strategy = SensitiveStrategy.ID_CARD)
        private String idCard;

        /**
         * 电话
         */
        @Sensitive(strategy = SensitiveStrategy.PHONE)
        private String phone;

        /**
         * 地址
         */
        @Sensitive(strategy = SensitiveStrategy.ADDRESS)
        private String address;

        /**
         * 邮箱
         */
        @Sensitive(strategy = SensitiveStrategy.EMAIL)
        private String email;

        /**
         * 银行卡
         */
        @Sensitive(strategy = SensitiveStrategy.BANK_CARD)
        private String bankCard;

    }

}

 

  博主精心整理专栏,CV大法即可用,感谢您小手点一点 手动跪拜:  

1- SpringBoot框架常用配置(若依),代码解读:

http://t.csdnimg.cn/jpsSN

2- java常用工具类整理,示例演示:

http://t.csdnimg.cn/gmCfJ

3- CompletableFuture 异步编排实际代码展示

http://t.csdnimg.cn/ZuC0N

4- XXL-JOB 详细学习,手把手带入门

http://t.csdnimg.cn/lyR7Y

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

syfjava

请博主喝杯蜜雪冰城

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值