注解进行数据脱敏处理

1.定义注解和枚举类

package com.joolun.common.sensitive;

import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 脱敏注解
 *
 * @author JooLun
 * @Author: https://www.cnblogs.com/xiluonanfeng/p/10183926.html
 **/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside
@JsonSerialize(using = SensitiveSerialize.class)
public @interface Sensitive {

    /**
     * 脱敏数据类型
     */
    SensitiveTypeEnum type();

}
package com.joolun.common.sensitive;

/**
 * 敏感信息枚举类
 *
 * @author JooLun
 * @Author: https://www.cnblogs.com/xiluonanfeng/p/10183926.html
 **/
public enum SensitiveTypeEnum {

    /**
     * 用户名, 李*天, 张*
     */
    CHINESE_NAME,
    /**
     * 手机号, 185****1653
     */
    MOBILE_PHONE,
    /**
     * 电子邮件, r*****o@qq.com
     */
    EMAIL,
    /**
     * 密码, ******
     */
    PASSWORD,
    /**
     * 密钥, 最后三位其他都是***
     */
    KEY

}

2.脱敏工具类和业务类

package com.joolun.common.sensitive;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.joolun.common.utils.SensitiveUtils;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;

import java.io.IOException;
import java.util.Objects;

/**
 * @author JooLun
 * @Author: https://www.cnblogs.com/xiluonanfeng/p/10183926.html
 * 脱敏序列化
 */
@NoArgsConstructor
@AllArgsConstructor
public class SensitiveSerialize extends JsonSerializer<String> implements ContextualSerializer {

    private SensitiveTypeEnum type;

    @Override
    public void serialize(final String originStr, final JsonGenerator jsonGenerator,
                          final SerializerProvider serializerProvider) throws IOException {
        switch (type) {
        case CHINESE_NAME:
            jsonGenerator.writeString(SensitiveUtils.chineseName(originStr));
            break;
        case MOBILE_PHONE:
            jsonGenerator.writeString(SensitiveUtils.mobilePhone(originStr));
            break;
        case EMAIL:
            jsonGenerator.writeString(SensitiveUtils.email(originStr));
            break;
        case PASSWORD:
            jsonGenerator.writeString(SensitiveUtils.password(originStr));
            break;
        case KEY:
            jsonGenerator.writeString(SensitiveUtils.key(originStr));
            break;
        default:
            throw new IllegalArgumentException("未定义的敏感信息枚举类" + type);
        }
    }

    @Override
    public JsonSerializer<?> createContextual(final SerializerProvider serializerProvider, final BeanProperty beanProperty) throws JsonMappingException {
        if (beanProperty != null) {
            if (Objects.equals(beanProperty.getType().getRawClass(), String.class)) {
                Sensitive sensitive = beanProperty.getAnnotation(Sensitive.class);
                if (sensitive == null) {
                    sensitive = beanProperty.getContextAnnotation(Sensitive.class);
                }
                if (sensitive != null) {
                    return new SensitiveSerialize(sensitive.type());
                }
            }
            return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
        }
        return serializerProvider.findNullValueSerializer(null);
    }

}
package com.joolun.common.utils;

import cn.hutool.core.util.StrUtil;

/**
 * 数据脱敏工具类
 *
 * @Author: JooLun
 * @Author: https://www.cnblogs.com/xiluonanfeng/p/10183926.html
 * @Date: 2021/7/19 16:21
 */
public class SensitiveUtils {

    /**
     * 默认填充字符
     */
    public static final String DEFAULT_PAD_STR = "*";

    /**
     * 数据脱敏
     *
     */
    public static String process(String data) {
        return process(data, 2, 1, DEFAULT_PAD_STR);
    }

    /**
     * 数据脱敏
     *
     */
    public static String process(String data, Integer leftLen, Integer rightLen) {
        return process(data, leftLen, rightLen, DEFAULT_PAD_STR);
    }

    /**
     * 对字符串进行脱敏操作
     * @param originStr 原始字符串
     * @param prefixNoMaskLen 左侧需要保留几位明文字段
     * @param suffixNoMaskLen 右侧需要保留几位明文字段
     * @param maskStr 用于遮罩的字符串, 如'*'
     * @return 脱敏后结果
     */
    public static String process(String originStr, int prefixNoMaskLen, int suffixNoMaskLen, String maskStr) {
        if (originStr == null) {
            return null;
        }

        StringBuilder sb = new StringBuilder();
        for (int i = 0, n = originStr.length(); i < n; i++) {
            if (i < prefixNoMaskLen) {
                sb.append(originStr.charAt(i));
                continue;
            }
            if (i > (n - suffixNoMaskLen - 1)) {
                sb.append(originStr.charAt(i));
                continue;
            }
            sb.append(maskStr);
        }
        return sb.toString();
    }

    /**
     * 中文姓名只显示最后一个汉字
     * @param fullName 姓名
     * @return
     */
    public static String chineseName(String fullName) {
        if (fullName == null) {
            return null;
        }
        return process(fullName, 0, 1, DEFAULT_PAD_STR);
    }

    /**
     * 手机号码前三位,后四位,如186****2356
     * @param num 手机号码
     * @return
     */
    public static String mobilePhone(String num) {
        return process(num, 0, 4, DEFAULT_PAD_STR);
    }

    /**
     * 地址只显示到地区
     * @param address 地址
     * @return
     */
    public static String address(String address) {
        return process(address, 6, 0, DEFAULT_PAD_STR);
    }

    /**
     * 电子邮箱 仅显示第一个字母,@后面的地址显示,比如:r**@qq.com
     * @param email 电子邮箱
     * @return
     */
    public static String email(String email) {
        if (email == null) {
            return null;
        }
        int index = StrUtil.indexOf(email, '@');
        if (index <= 1) {
            return email;
        }
        String preEmail = process(email.substring(0, index), 1, 0, DEFAULT_PAD_STR);
        return preEmail + email.substring(index);

    }

    /**
     * 密码的全部字符,如:******
     * @param password 密码
     * @return
     */
    public static String password(String password) {
        if (password == null) {
            return null;
        }
        return "******";
    }

    /**
     * 密钥除了最后三位,全部,比如:***klo
     * @param key 密钥
     * @return 结果
     */
    public static String key(String key) {
        if (key == null) {
            return null;
        }
        int viewLength = 6;
        StringBuilder tmpKey = new StringBuilder(process(key, 0, 3, DEFAULT_PAD_STR));
        if (tmpKey.length() > viewLength) {
            return tmpKey.substring(tmpKey.length() - viewLength);
        }
        else if (tmpKey.length() < viewLength) {
            int buffLength = viewLength - tmpKey.length();
            for (int i = 0; i < buffLength; i++) {
                tmpKey.insert(0, DEFAULT_PAD_STR);
            }
            return tmpKey.toString();
        }
        else {
            return tmpKey.toString();
        }
    }

    public static void main(String[] args) {
        String s = mobilePhone("18653653621");
        System.out.println(s);
    }
}

3.实体类使用

  /**
   * 电话号码
   */
    @ApiModelProperty(value = "电话号码")
    @Sensitive(type = SensitiveTypeEnum.MOBILE_PHONE)
    private String telNum;

 

posted on 2022-11-30 21:43  AnkangWenqiang  阅读(117)  评论(0编辑  收藏  举报

导航