注解实现数据脱敏

信息脱敏工具类

/**
 * 脱敏工具类
 *
 */
@Component
public class DesensitizationUtil {

    private static final Integer ZERO = 0;
    /**
     * 脱敏类型map
     * key:脱敏类型
     * value:lambda表达式,脱敏方法
     * Function<搜索条件,返回结果>
     */
    private final static Map<DesensitizationEnum, Function<String, String>> DES_MAP = new HashMap<>();

    /**
     *初始化分派逻辑,代替if-else
     */
    @PostConstruct
    public void desMapInit() {
        //姓名
        DES_MAP.put(DesensitizationEnum.USER_NAME, DesensitizationUtil::getDecName);
        //身份证号码普通脱敏
        DES_MAP.put(DesensitizationEnum.COMMON_ID_CARD, DesensitizationUtil::getDecIdNum);
        //身份证号码强脱敏
        DES_MAP.put(DesensitizationEnum.STRONG_ID_CARD, DesensitizationUtil::getDecIdNumStrongEn);
        //手机号码
        DES_MAP.put(DesensitizationEnum.MOBILE_PHONE, DesensitizationUtil::getDecMobile);
        //固定电话
        DES_MAP.put(DesensitizationEnum.FIXED_TELEPHONE, DesensitizationUtil::getDecTelephone);
        //邮箱
        DES_MAP.put(DesensitizationEnum.MAIL, DesensitizationUtil::getDecEmail);
        //银行卡号
        DES_MAP.put(DesensitizationEnum.BANK_NO, DesensitizationUtil::getDecBankNum);
        //住址
        DES_MAP.put(DesensitizationEnum.ADDRESS, DesensitizationUtil::getDecAddr);
        //其它脱敏(军官证号、护照号等其他身份证件)
        DES_MAP.put(DesensitizationEnum.OTHER, DesensitizationUtil::getDecOther);
    }

    /**
     * 脱敏方法入口
     *
     * @param type 脱敏类型
     * @param src  源数据
     * @return String 脱敏后数据
     */
    public static String getDesString(DesensitizationEnum type, String src) {
        Function<String, String> function = DES_MAP.get(type);
        if (!ObjectUtils.isEmpty(function)) {
            return function.apply(src);
        }
        return "";
    }

    /**
     * 姓名脱敏
     *
     * @param name 姓名
     * @return String
     */
    public static String getDecName(String name) {
        if (!StringUtils.isEmpty(name)) {
            name = "*" + name.substring(1);
        }
        return name;
    }

    /**
     * 身份证号普通脱敏
     * <p>
     * 显示前1、5、6、7、8、9、10、11、12、18位,其余用*号代替
     *
     * @param idNum 身份证号
     * @return String
     */
    public static String getDecIdNum(String idNum) {
        //显示前1、5、6、7、8、9、10、11、12、18位,其余用*号代替。
        if (idNum != null && idNum.length() > 12) {
            idNum = idNum.substring(0, 1) + "***" + idNum.substring(4, 12) + "*****" + idNum.substring(idNum.length() - 1);
        }
        return idNum;
    }

    /**
     * 身份证号强脱敏
     * <p>
     * 3****************8
     *
     * @param idNum 身份证号
     * @return String
     */
    public static String getDecIdNumStrongEn(String idNum) {
        //3****************8
        if (idNum != null && idNum.length() > 12) {
            idNum = idNum.substring(0, 1) + "****************" + idNum.substring(idNum.length() - 1);
        }
        return idNum;
    }

    /**
     * 手机号码脱敏
     *
     * @param mobile 手机号
     * @return String
     */
    public static String getDecMobile(String mobile) {
        if (mobile != null && mobile.length() == 11) {
            mobile = mobile.substring(0, 3) + "****" + mobile.substring(mobile.length() - 4);
        }
        return mobile;
    }

    /**
     * 固定电话脱敏
     *
     * @param telephone 固定电话
     * @return String
     */
    public static String getDecTelephone(String telephone) {
        if (telephone != null) {
            if (telephone.length() > 10) {
                telephone = String.format("%s****%s", telephone.substring(0, 4), telephone.substring(telephone.length() - 4));
            } else if (telephone.length() > 4) {
                telephone = "****" + telephone.substring(telephone.length() - 4);
            }
        }
        return telephone;
    }

    /**
     * 邮箱脱敏
     * <p>
     * 前面的字符显示3位,3位后显示3个*,@后面完整显示 如:con***@163.com
     * 如果少于三位,则全部显示,@前加***,例如tt@163.com 则显示为tt***@163.com
     *
     * @param email 邮箱
     * @return String
     */
    public static String getDecEmail(String email) {
        String[] emialSplit = email.split("@");
        String befor = "";
        if (emialSplit[0].length() > 2) {
            befor = emialSplit[0].substring(0, 3) + "***" + "@" + emialSplit[1];
        } else {
            befor = emialSplit[0] + "***" + "@" + emialSplit[1];
        }
        return befor;
    }

    /**
     * 银行卡号脱敏
     * <p>
     * 显示前6位+ *(实际位数)+后4位。 如:622575******1496
     *
     * @param bankNum 银行卡号
     * @return String
     */
    public static String getDecBankNum(String bankNum) {
        if (bankNum.length() > 10) {
            String xy = bankNum.substring(0, 6) + bankNum.substring(bankNum.length() - 4);
            int length = bankNum.length() - xy.length();
            String slip = "";
            for (int i = 0; i < length; i++) {
                slip += "*";
            }
            bankNum = bankNum.substring(0, 6) + slip + bankNum.substring(bankNum.length() - 4);

        }
        return bankNum;
    }

    /**
     * 住址脱敏
     * <p>
     * 将最后一个数字脱敏
     *
     * @param address 住址
     * @return String
     */
    public static String getDecAddr(String address) {
        if (!StringUtils.isEmpty(address)) {
            for (int i = 0; i < address.length(); i++) {
                boolean needDec = (address.charAt(i) >= 48 && address.charAt(i) <= 57)
                        || (address.charAt(i) >= 65296 && address.charAt(i) <= 65305);
                if (needDec) {
                    address = address.replace(String.valueOf(address.charAt(i)), "*");
                }
            }
        }
        return address;
    }

    /**
     * 其它脱敏
     * <p>
     * 显示前1/3和后1/3
     * <p>
     * 军官证号、护照号等其他身份证件
     *
     * @param src 源数据
     * @return String
     */
    public static String getDecOther(String src) {
        String rtn = src;
        if (!StringUtils.isEmpty(src)) {
            int b = src.length() / 3;
            rtn = src.substring(0, b);
            for (int i = b; i < src.length() - b; i++) {
                rtn += "*";
            }
            rtn += src.substring(b * 2);
        }
        return rtn;
    }

    /**
     * 根据身份号码获取生日
     *
     * @param idNum 身份证号
     * @return String 生日 yyyy-MM-dd
     */
    public static String getBirthByIdNum(String idNum) {
        String birth = "";
        if (idNum != null && idNum.length() == 18) {
            String year = idNum.substring(6, 10);
            String moth = idNum.substring(10, 12);
            String day = idNum.substring(12, 14);
            birth = year + "-" + moth + "-" + day;
        }
        return birth;
    }

    /**
     * 根据身份证号码获取性别
     *
     * @param idNum 身份证号
     * @return String 性别类别 1-男,2-女
     */
    public static int getSexByIdNum(String idNum) {
        int sex = 0;
        if (idNum != null && idNum.length() == 18) {
            String sCardNum = idNum.substring(16, 17);
            if (Integer.parseInt(sCardNum) % 2 != 0) {
                //男
                sex = 1;
            } else {
                //女
                sex = 2;
            }
        }
        return sex;
    }

    /**
     * 根据身份证号获取年龄
     *
     * @param idNum 身份证号
     * @return String 年龄
     */
    public static int getAgeByIdNum(String idNum) {
        if (StringUtils.isBlank(idNum)) {
            return ZERO;
        }
        String birthday = getBirthByIdNum(idNum);
        return getAgeByBirthday(birthday);
    }

    /**
     * 根据出生日期获取年龄
     *
     * @param birthday 出生日期
     * @return int
     */
    public static int getAgeByBirthday(String birthday) {
        if (StringUtils.isBlank(birthday)) {
            return ZERO;
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date birth = new Date();
        try {
            birth = sdf.parse(birthday);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return getAgeByBirthday(birth);
    }

    /**
     * 根据出生日期获取年龄
     *
     * @param birthday 出生日期
     * @return int
     */
    public static int getAgeByBirthday(Date birthday) {
        Calendar cal = Calendar.getInstance();
        //出生日期晚于当前时间,无法计算
        if (cal.before(birthday)) {
            return ZERO;
        }
        //当前年份
        int yearNow = cal.get(Calendar.YEAR);
        //当前月份
        int monthNow = cal.get(Calendar.MONTH);
        //当前日期
        int dayOfMonthNow = cal.get(Calendar.DAY_OF_MONTH);
        cal.setTime(birthday);
        int yearBirth = cal.get(Calendar.YEAR);
        int monthBirth = cal.get(Calendar.MONTH);
        int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);
        //计算整岁数
        int age = yearNow - yearBirth;
        if (monthNow <= monthBirth) {
            if (monthNow == monthBirth) {
                //当前日期在生日之前,年龄减一
                if (dayOfMonthNow < dayOfMonthBirth) {
                    age--;
                }
            } else {
                //当前月份在生日之前,年龄减一
                age--;
            }
        }
        return age;
    }

    /**
     * 根据出生日期和指定日期获取年龄
     *
     * @param birthday     出生日期
     * @param appointedDay 指定日期
     * @return int
     */
    public static int getAgeByBirthday(Date birthday, Date appointedDay) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(appointedDay);
        //出生日期晚于当前时间,无法计算
        if (cal.before(birthday)) {
            return ZERO;
        }
        //当前年份
        int yearNow = cal.get(Calendar.YEAR);
        //当前月份
        int monthNow = cal.get(Calendar.MONTH);
        //当前日期
        int dayOfMonthNow = cal.get(Calendar.DAY_OF_MONTH);
        cal.setTime(birthday);
        int yearBirth = cal.get(Calendar.YEAR);
        int monthBirth = cal.get(Calendar.MONTH);
        int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);
        //计算整岁数
        int age = yearNow - yearBirth;
        if (monthNow <= monthBirth) {
            if (monthNow == monthBirth) {
                //当前日期在生日之前,年龄减一
                if (dayOfMonthNow < dayOfMonthBirth) {
                    age--;
                }
            } else {
                //当前月份在生日之前,年龄减一
                age--;
            }
        }
        return age;
    }
}

自定义注解

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = DesensitizationSerializer.class)
public @interface Desensitization {

    /**
     * 脱敏类型
     */
    DesensitizationEnum type() default DesensitizationEnum.OTHER;

    /**
     * 判断是否需要返回前端未脱敏的值 默认不需要
     */
    boolean originalFieldValue() default false;
}

自定义序列化类

/**
 * 序列化脱敏字段
 *
 * @version 版 本 号:1.0
 * @since 2022-08-19 14:15
 */
public class DesensitizationSerializer extends StdSerializer<Object> implements ContextualSerializer {

    private static final long serialVersionUID = 3205040278266130966L;
    /**
     * 脱敏类型
     */
    private DesensitizationEnum type;
    /**
     * 判断是否需要返回前端未脱敏的值
     */
    private Boolean originalFieldValue;

    public DesensitizationSerializer() {
        super(Object.class);
    }

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
        if (Objects.isNull(beanProperty)) {
            return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
        }
        Desensitization annotation = beanProperty.getAnnotation(Desensitization.class);
        if (Objects.nonNull(annotation)) {
            type = annotation.type();
            originalFieldValue = annotation.originalFieldValue();
            return this;
        }
        return serializerProvider.findNullValueSerializer(null);
    }

    @Override
    public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        if (Objects.isNull(o)) {
            return;
        }
        String label = DesensitizationUtil.getDesString(type, o.toString());
        //判断是否需要将未脱敏值返回前端
        if (originalFieldValue) {
            //原文base64加密
            String encodeToString = Base64.getEncoder().encodeToString(o.toString().getBytes());
            jsonGenerator.writeObject(encodeToString);
        } else {
            jsonGenerator.writeObject("");
        }
        jsonGenerator.writeFieldName(jsonGenerator.getOutputContext().getCurrentName() + "Des");
        jsonGenerator.writeObject(label);
    }
}

使用

将注解加在需要脱敏的字段上

 	 /**
     * 手机号
     */
    @Desensitization(type = DesensitizationEnum.MOBILE_PHONE)
    private String ownerPhone;
  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

芝士汉堡 ིྀིྀ

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值