Java注解实现敏感数据脱敏

该文章介绍了一个Java实现的敏感信息脱敏工具类,包括手机号、身份证号、姓名、地址、邮箱、银行卡号和车牌号的脱敏方法。同时,文章还展示了自定义注解`SensitiveField`用于标记需要脱敏的字段,以及一个基于AOP的脱敏拦截器,用于在执行方法前后自动处理注解标记的敏感字段。
摘要由CSDN通过智能技术生成

一、创建一个脱敏工具类

package com.example.utils;

import org.apache.commons.lang3.StringUtils;

/**
 * 敏感信息脱敏工具类
 *
 * @Description
 * @Author WL
 * @Date 2023/7/20
 **/

public class MaskUtil {

    /**
     * 手机号脱敏
     * @param phone
     * @return
     */
    public final static String maskPhone(String phone){
        if(phone==null || phone.length()!=11) {
            return phone;
        }
        return StringUtils.join(phone.substring(0,3)+"******"+phone.substring(9));
    }

    /**
     * 身份证号脱敏
     * @param id
     * @return
     */
    public final static String maskIdCard(String id){
        if(id==null || id.length()!=18) {
            return id;
        }
        return StringUtils.join(id.substring(0,6)+"****");
    }

    /**
     *中文姓名脱敏
     * @param fullName
     * @return
     */
    public final static String chineseName(String fullName) {
        if(StringUtils.isBlank(fullName)) {
            return fullName;
        }
        String name = StringUtils.left(fullName, 1);
        return StringUtils.rightPad(name, StringUtils.length(fullName), "*");
    }

    /**
     *家庭住址脱敏
     * @param address
     * @param sensitiveSize 敏感信息长度
     * @return
     */
    public final static String address(String address, int sensitiveSize) {
        if(StringUtils.isBlank(address)) {
            return address;
        }
        int length = StringUtils.length(address);
        return StringUtils.rightPad(StringUtils.left(address, length - sensitiveSize), length - sensitiveSize+4, "*");
    }

    /**
     *邮箱脱敏
     * @param email
     * @return
     */
    public final static String email(String email) {
        if (StringUtils.isBlank(email)) {
            return email;
        }
        int index = StringUtils.indexOf(email, "@");
        if(index <= 1) {
            return email;
        } else {
            return StringUtils.rightPad(StringUtils.left(email, 1), index, "*").concat(StringUtils.mid(email, index, StringUtils.length(email)));
        }
    }

    /**
     *银行卡号脱敏
     * @param cardNum
     * @return
     */
    public final static String bankCard(String cardNum) {
        if(StringUtils.isBlank(cardNum)) {
            return cardNum;
        }
        return StringUtils.left(cardNum, 6).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(cardNum, 4), StringUtils.length(cardNum), "*"), "******"));
    }

    /**
     *固定电话脱敏
     * @param num
     * @return
     */
    public final static String fixedPhone(String num) {
        if(StringUtils.isBlank(num)) {
            return num;
        }
        return StringUtils.leftPad(StringUtils.right(num, 4), StringUtils.length(num), "*");
    }

    /**
     * 【中国车牌】车牌中间用*代替 eg1:null -》 "" eg1:"" -》 "" eg3:苏D40000 -》 苏D4***0 eg4:陕A12345D -》 陕A1****D eg5:京A123 -》 京A123 如果是错误的车牌,不处理
     *
     * @param carLicense 完整的车牌号
     * @return 脱敏后的车牌号
     */
    public static String carLicense(String carLicense) {
        if (StringUtils.isBlank(carLicense)) {
            return "";
        } else {
            if (carLicense.length() == 7) {
                carLicense = StringUtils.join(carLicense.substring(0,3)+"***"+carLicense.substring(6));
            } else if (carLicense.length() == 8) {
                carLicense = StringUtils.join(carLicense.substring(0,3)+"***"+carLicense.substring(7));
            }

            return carLicense;
        }
    }
}


二、编写自定义注解

package com.example.config.interfaces;

import java.lang.annotation.*;

/**
 * 脱敏信息注解
 *
 * @Description
 * @Author WL
 * @Date 2023/7/20
 **/

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SensitiveField {

    SensitiveTypeEnum value() default SensitiveTypeEnum.IDCARD;

    enum SensitiveTypeEnum {
        IDCARD,
        PHONE,
        NAME,
        ADDRESS,
        BANK,
        CARLICENSE,
    }

}

三、脱敏拦截

package com.example.config.interfaces;


import com.example.utils.MaskUtil;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;

/**
 *
 *
 * @Description
 * @Author WL
 * @Date 2023/7/20
 **/
@Aspect
@Configuration
public class SensitiveAspect {
    public static final String ACCESS_EXECUTION = "execution(* com.example..*.*(..))";
    /**
     * 注解脱敏处理
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around(ACCESS_EXECUTION)
    public Object sensitiveClass(ProceedingJoinPoint joinPoint) throws Throwable {
        return sensitiveFormat(joinPoint);
    }

    /**
     * 插拔式注解统一拦截器。@SensitiveField
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    public Object sensitiveFormat(ProceedingJoinPoint joinPoint) throws Throwable {
        Object obj = joinPoint.proceed();
        if (obj == null || isPrimitive(obj.getClass())) {
            return obj;
        }
        for (Field field : obj.getClass().getDeclaredFields()) {
            ReflectionUtils.makeAccessible(field);
            SensitiveField sensitiveField = field.getAnnotation(SensitiveField.class);
            if (sensitiveField != null) {
                Object value = field.get(obj);
                switch (sensitiveField.value()) {
                    case IDCARD:
                        String idCard = MaskUtil.maskIdCard((String) value);
                        ReflectionUtils.setField(field, obj, idCard);
                        break;
                    case PHONE:
                        String phone = MaskUtil.maskPhone((String) value);
                        ReflectionUtils.setField(field, obj, phone);
                        break;
                    case NAME:
                        String name = MaskUtil.chineseName((String) value);
                        ReflectionUtils.setField(field, obj, name);
                        break;
                    case ADDRESS:
                        //TODO
                        String address = MaskUtil.address((String) value, StringUtils.length((String) value));
                        ReflectionUtils.setField(field, obj, address);
                        break;
                    case BANK:
                        //TODO
                        String bankCard = MaskUtil.bankCard((String) value);
                        ReflectionUtils.setField(field, obj, bankCard);
                        break;
                    case CARLICENSE:
                        //TODO
                        String carLicense = MaskUtil.carLicense((String) value);
                        ReflectionUtils.setField(field, obj, carLicense);
                        break;
                    default:
                        break;
                }
            }
        }
        return obj;
    }


    /**
     * 基本数据类型和String类型判断
     *
     * @param clz
     * @return
     */
    private boolean isPrimitive(Class<?> clz) {
        try {
            if (String.class.isAssignableFrom(clz) || clz.isPrimitive()) {
                return true;
            } else {
                return ((Class) clz.getField("TYPE").get(null)).isPrimitive();
            }
        } catch (Exception e) {
            return false;
        }
    }

}

四、编写一个对象使用注解

package com.example.model;

import com.example.config.interfaces.SensitiveField;
import lombok.Data;

/**
 * TODO
 *
 * @Description
 * @Author WL
 * @Date 2023/7/20
 **/
@Data
public class MskDto {
    @SensitiveField(SensitiveField.SensitiveTypeEnum.IDCARD)
    private String idCard;

    @SensitiveField(SensitiveField.SensitiveTypeEnum.NAME)
    private String complainantName;

    @SensitiveField(SensitiveField.SensitiveTypeEnum.PHONE)
    private String respondentPhone;

    @SensitiveField(SensitiveField.SensitiveTypeEnum.BANK)
    private String bankCard;

    @SensitiveField(SensitiveField.SensitiveTypeEnum.CARLICENSE)
    private String carLicense;
}

五、验证Controller

package com.example.controller;

import com.example.model.MskDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

/**
 * TODO
 *
 * @Description
 * @Author WL
 * @Date 2023/7/20
 **/
@Slf4j
@RequestMapping("/mas")
@RestController
public class MasController {

    @PostMapping("/test")
    public MskDto sayHelloMqTest(@RequestBody MskDto request) throws Exception{
        log.info("idcard: {}", request.getIdCard().toString());
        log.info("name: {}", request.getComplainantName());
        log.info("phone: {}", request.getRespondentPhone());
        return request;
    }

}

六、验证结果

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值