aaaddddddddd

com.lemon.mask.annotation;
/**
 * @author lemon
 * @description 数据脱敏注解
 * @date 2020-07-01 19:00
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
@JacksonAnnotationsInside
@JsonSerialize(using = JacksonDataMaskSerializer.class)
public @interface DataMask {
    /**
     * 脱敏数据类型
     */
    SensitiveType sensitiveType() default SensitiveType.DEFAULT;

    /**
     * 开始N个字符不脱敏
     */
    int prefixNoMaskSize() default Integer.MIN_VALUE;

    /**
     * 结尾N个字符不脱敏
     */
    int suffixNoMaskSize() default Integer.MIN_VALUE;

    /**
     * 脱敏字符串
     */
    String maskFlag() default "*";
}
com.lemon.mask.annotation;
/**
 * @author lemon
 * @description 数据脱敏类型注解
 * @date 2020-07-01 19:00
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DataMaskType {

    /**
     * 脱敏类型
     */
    SensitiveType sensitiveType();
}
com.lemon.mask.builder;
import com.lemon.mask.annotation.DataMask;
import com.lemon.mask.strategy.DesensitizedConfig;
import com.lemon.mask.util.DesensitizedUtils;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.util.Arrays;

/**
 * @author lemon
 * @description 数据脱敏:重写toString方法实现数据脱敏
 * @date 2020-07-03 16:06
 */
public class DataMaskToStringBuilder extends ReflectionToStringBuilder {
    private boolean excludeNullValues = true;

    /**
     * @param object
     * @return
     * @description
     * @author lemon
     * @date 2020-07-03 17:29
     */
    public DataMaskToStringBuilder(Object object) {
        super(object);
    }

    /**
     * @param object
     * @param style
     * @return
     * @description
     * @author lemon
     * @date 2020-07-03 17:29
     */
    public DataMaskToStringBuilder(Object object, ToStringStyle style) {
        super(object, style);
    }

    /**
     * @param object
     * @param style
     * @return
     * @description
     * @author lemon
     * @date 2020-07-03 17:29
     */
    public DataMaskToStringBuilder(Object object, boolean excludeNullValues, ToStringStyle style) {
        super(object, style);
        this.excludeNullValues = excludeNullValues;
    }

    /**
     * @param clazz
     * @return void
     * @description
     * @author lemon
     * @date 2020-07-03 17:29
     */
    @Override
    protected void appendFieldsIn(Class clazz) {
        if (clazz.isArray()) {
            this.reflectionAppendArray(this.getObject());
            return;
        }

        Field[] fields = clazz.getDeclaredFields();
        AccessibleObject.setAccessible(fields, true);
        Arrays.stream(fields).forEach(this::appendFieldIn);
    }

    /**
     * @param field
     * @return void
     * @description
     * @author lemon
     * @date 2020-07-03 17:32
     */
    protected void appendFieldIn(Field field) {
        String fieldName = field.getName();

        if (!this.accept(field)) {
            return;
        }

        try {
            Object fieldValue = this.getValue(field);

            if (this.excludeNullValues && fieldValue == null) {
                return;
            }

            // 如果需要脱敏
            DataMask dataMask = field.getAnnotation(DataMask.class);

            if (dataMask == null || field.getType() != String.class) {
                this.append(fieldName, fieldValue);
            } else {
                this.appendMaskFieldIn(fieldName, (String) fieldValue, dataMask);
            }
        } catch (IllegalAccessException ex) {
            throw new InternalError("Unexpected IllegalAccessException: " + ex.getMessage());
        }
    }

    /**
     * @param fieldName
     * @param fieldValue
     * @param dataMask
     * @return void
     * @description
     * @author lemon
     * @date 2020-07-03 17:32
     */
    protected void appendMaskFieldIn(String fieldName, String fieldValue, DataMask dataMask) {
        DesensitizedConfig desensitizedConfig = DesensitizedUtils.getDesensitizedConfig(dataMask);
        this.append(fieldName, DesensitizedUtils.maskValue(fieldValue, desensitizedConfig));
    }
}
com.lemon.mask.enumeration;
/**
 * @author lemon
 * @description 数据脱敏类型
 * @date 2020-07-03 14:15
 */
public enum SensitiveType {
    /**
     * 默认脱敏策略
     */
    DEFAULT,
    /**
     * 中文名
     */
    CHINESE_NAME,
    /**
     * 身份证号
     */
    ID_CARD,
    /**
     * 座机号
     */
    FIXED_PHONE,
    /**
     * 手机号
     */
    MOBILE_PHONE,
    /**
     * 地址
     */
    ADDRESS,
    /**
     * 电子邮件
     */
    EMAIL,
    /**
     * 银行卡
     */
    BANK_CARD,
    /**
     * 公司开户银行联号
     */
    CNAPS_CODE,
    /**
     * 密码
     */
    PASSWORD,
    /**
     * 车牌号
     */
    CARNUMBER;
}
com.lemon.mask.serializer;
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.lemon.mask.annotation.DataMask;
import com.lemon.mask.strategy.DataMaskStrategy;
import com.lemon.mask.strategy.DataMaskStrategyContext;
import com.lemon.mask.strategy.DesensitizedConfig;
import com.lemon.mask.util.DesensitizedUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

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

/**
 * @author lemon
 * @version 1.0
 * @description: 服务返回数据脱敏
 * @date Create by lemon on 2020-07-03 21:08
 */
@Slf4j
public class JacksonDataMaskSerializer extends JsonSerializer<String> implements ContextualSerializer {
    private DesensitizedConfig desensitizedConfig;

    public JacksonDataMaskSerializer() {

    }

    public JacksonDataMaskSerializer(DesensitizedConfig desensitizedConfig) {
        this.desensitizedConfig = desensitizedConfig;
    }

    /**
     * Method that can be called to ask implementation to serialize
     * values of type this serializer handles.
     *
     * @param value         Value to serialize; can <b>not</b> be null.
     * @param jsonGenerator Generator used to output resulting Json content
     * @param serializers   Provider that can be used to get serializers for
     */
    @Override
    public void serialize(String value, JsonGenerator jsonGenerator, SerializerProvider serializers) throws IOException {
        if (StringUtils.isBlank(value)) {
            jsonGenerator.writeObject(value);
            return;
        }

        if (desensitizedConfig == null) {
            log.debug("Not mask");
            jsonGenerator.writeObject(value);
            return;
        }

        DataMaskStrategy maskStrategy = DataMaskStrategyContext.getDataMaskStrategy(desensitizedConfig.getSensitiveType());

        if (maskStrategy == null) {
            log.warn("No matching Mask Strategy found for type [{}]", desensitizedConfig.getSensitiveType());
            jsonGenerator.writeObject(value);
            return;
        }

        String newValue = maskStrategy.mask(desensitizedConfig, value);

        log.debug("Find MaskStrategy [{}]", maskStrategy.getClass());
        jsonGenerator.writeString(newValue);
    }

    /**
     * Method called to see if a different (or differently configured) serializer
     * is needed to serialize values of specified property.
     * Note that instance that this method is called on is typically shared one and
     * as a result method should <b>NOT</b> modify this instance but rather construct
     * and return a new instance. This instance should only be returned as-is, in case
     * it is already suitable for use.
     *
     * @param prov     Serializer provider to use for accessing config, other serializers
     * @param property Method or field that represents the property
     *                 (and is used to access value to serialize).
     *                 Should be available; but there may be cases where caller cannot provide it and
     *                 null is passed instead (in which case impls usually pass 'this' serializer as is)
     * @return Serializer to use for serializing values of specified property;
     * may be this instance or a new instance.
     * @throws JsonMappingException
     */
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
        if (property == null) {
            return prov.findNullValueSerializer(null);
        }

        if (Objects.equals(property.getType().getRawClass(), String.class)) {
            DataMask dataMask = property.getAnnotation(DataMask.class);

            if (dataMask == null) {
                dataMask = property.getContextAnnotation(DataMask.class);
            }

            if (dataMask != null) {
                DesensitizedConfig desensitizedConfig = DesensitizedUtils.getDesensitizedConfig(dataMask);
                return new JacksonDataMaskSerializer(desensitizedConfig);
            }
        }

        return prov.findValueSerializer(property.getType(), property);
    }
}
com.lemon.mask.strategy;

import com.lemon.mask.annotation.DataMaskType;
import com.lemon.mask.enumeration.SensitiveType;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author lemon
 * @version 1.0
 * @description: [地址] 只显示到地区,不显示详细地址;我们要对个人信息增强保护<例子:北京市海淀区****>
 * @date Create by lemon on 2020-07-03 14:53
 */
@Getter
@Component
@DataMaskType(sensitiveType = SensitiveType.ADDRESS)
public class Address implements DataMaskStrategy {
    @Value("${mask.prefixNoMaskSize:6}")
    private int prefixNoMaskSize;

    @Value("${mask.suffixNoMaskSize:0}")
    private int suffixNoMaskSize;

    @Value("${mask.maskFlag:*}")
    private String maskFlag;

    /**
     * @param original
     * @return java.lang.String
     * @description [地址] 只显示到地区,不显示详细地址;我们要对个人信息增强保护<例子:北京市海淀区****>
     * @author lemon
     * @date 2020-07-03 14:51
     */
    @Override
    public String mask(String original) {
        if (StringUtils.isBlank(original)) {
            return original;
        }

        return mask(original, prefixNoMaskSize, suffixNoMaskSize, maskFlag);
    }
}

import com.lemon.mask.annotation.DataMaskType;
import com.lemon.mask.enumeration.SensitiveType;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author lemon
 * @version 1.0
 * @description: [银行卡号] 前六位,后四位,其他用星号隐藏每位1个星号<例子:6222600**********1234>
 * @date Create by lemon on 2020-07-03 14:53
 */
@Getter
@Component
@DataMaskType(sensitiveType = SensitiveType.BANK_CARD)
public class BankCard implements DataMaskStrategy {
    @Value("${mask.prefixNoMaskSize:6}")
    private int prefixNoMaskSize;

    @Value("${mask.suffixNoMaskSize:4}")
    private int suffixNoMaskSize;

    @Value("${mask.maskFlag:*}")
    private String maskFlag;

    /**
     * @param original
     * @return java.lang.String
     * @description [银行卡号] 前六位,后四位,其他用星号隐藏每位1个星号<例子:6222600**********1234>
     * @author lemon
     * @date 2020-07-03 14:51
     */
    @Override
    public String mask(String original) {
        if (StringUtils.isBlank(original)) {
            return original;
        }

        return mask(original, prefixNoMaskSize, suffixNoMaskSize, maskFlag);
    }
}
import com.lemon.mask.annotation.DataMaskType;
import com.lemon.mask.enumeration.SensitiveType;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author lemon
 * @version 1.0
 * @description: 【车牌号】前两位后一位,比如:京A****5
 * @date Create by lemon on 2020-07-03 14:53
 */
@Getter
@Component
@DataMaskType(sensitiveType = SensitiveType.CARNUMBER)
public class CarNumber implements DataMaskStrategy {
    @Value("${mask.prefixNoMaskSize:2}")
    private int prefixNoMaskSize;

    @Value("${mask.suffixNoMaskSize:1}")
    private int suffixNoMaskSize;

    @Value("${mask.maskFlag:*}")
    private String maskFlag;

    /**
     * @param original
     * @return java.lang.String
     * @description 【车牌号】前两位后一位,比如:京A****5
     * @author lemon
     * @date 2020-07-03 14:51
     */
    @Override
    public String mask(String original) {
        if (StringUtils.isBlank(original)) {
            return original;
        }

        return mask(original, prefixNoMaskSize, suffixNoMaskSize, maskFlag);
    }
}
import com.lemon.mask.annotation.DataMaskType;
import com.lemon.mask.enumeration.SensitiveType;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author lemon
 * @version 1.0
 * @description: [中文姓名] 只显示第一个汉字,其他隐藏为2个星号<例子:李**>
 * @date Create by lemon on 2020-07-03 14:53
 */
@Getter
@Component
@DataMaskType(sensitiveType = SensitiveType.CHINESE_NAME)
public class ChineseName implements DataMaskStrategy {
    @Value("${mask.prefixNoMaskSize:1}")
    private int prefixNoMaskSize;

    @Value("${mask.suffixNoMaskSize:1}")
    private int suffixNoMaskSize;

    @Value("${mask.maskFlag:*}")
    private String maskFlag;

    /**
     * @param original
     * @return java.lang.String
     * @description [中文姓名] 只显示第一个汉字,其他隐藏为2个星号<例子:李**>
     * @author lemon
     * @date 2020-07-03 14:51
     */
    @Override
    public String mask(String original) {
        if (StringUtils.isBlank(original)) {
            return original;
        }

        if (original.length() > 2) {
            return mask(original, prefixNoMaskSize, suffixNoMaskSize, maskFlag);
        } else {
            return mask(original, 1, 0);
        }
    }
}
import com.lemon.mask.annotation.DataMaskType;
import com.lemon.mask.enumeration.SensitiveType;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author lemon
 * @version 1.0
 * @description: [公司开户银行联号] 公司开户银行联行号,显示前两位,其他用星号隐藏,每位1个星号<例子:12********>
 * @date Create by lemon on 2020-07-03 14:53
 */
@Getter
@Component
@DataMaskType(sensitiveType = SensitiveType.CNAPS_CODE)
public class CnapsCode implements DataMaskStrategy {
    @Value("${mask.prefixNoMaskSize:2}")
    private int prefixNoMaskSize;

    @Value("${mask.suffixNoMaskSize:0}")
    private int suffixNoMaskSize;

    @Value("${mask.maskFlag:*}")
    private String maskFlag;

    /**
     * @param original
     * @return java.lang.String
     * @description [公司开户银行联号] 公司开户银行联行号,显示前两位,其他用星号隐藏,每位1个星号<例子:12********>
     * @author lemon
     * @date 2020-07-03 14:51
     */
    @Override
    public String mask(String original) {
        if (StringUtils.isBlank(original)) {
            return original;
        }

        return mask(original, prefixNoMaskSize, suffixNoMaskSize, maskFlag);
    }
}

/**
 * @author lemon
 * @version 1.0
 * @description: 脱敏配置
 * @date Create by lemon on 2020-07-04 07:11
 */
public interface DataMaskConfig {
    /**
     * @param
     * @return java.lang.String
     * @description 前置不需要脱敏的长度
     * @author lemon
     * @date 2020-07-04 07:13
     */
    int getPrefixNoMaskSize();

    /**
     * @param
     * @return java.lang.String
     * @description 后置不需要脱敏的长度
     * @author lemon
     * @date 2020-07-04 07:13
     */
    int getSuffixNoMaskSize();

    /**
     * @param
     * @return java.lang.String
     * @description 脱敏字符串
     * @author lemon
     * @date 2020-07-04 07:13
     */
    String getMaskFlag();
}
package com.lemon.mask.strategy;

import org.apache.commons.lang3.StringUtils;

/**
 * @author lemon
 * @version 1.0
 * @description: 数据脱敏策略
 * @date Create by lemon on 2020-07-03 14:26
 */
public interface DataMaskStrategy extends DataMaskConfig {
    /**
     * @param original
     * @return java.lang.String
     * @description 原始数据脱敏处理
     * @author lemon
     * @date 2020-07-03 14:51
     */
    String mask(String original);

    /**
     * @param desensitizedConfig
     * @param original
     * @return java.lang.String
     * @description 原始数据脱敏处理
     * @author lemon
     * @date 2020-07-04 07:08
     */
    default String mask(DesensitizedConfig desensitizedConfig, String original) {
        if (StringUtils.isBlank(original)) {
            return original;
        }

        return this.mask(original, desensitizedConfig.getPrefixNoMaskSize(), desensitizedConfig.getSuffixNoMaskSize(),
                desensitizedConfig.getMaskFlag());
    }

    /**
     * @param original        原始数据
     * @param prefixNoMaskSize 开始N个字符不脱敏
     * @param suffixNoMaskSize 结尾N个字符不脱敏
     * @return java.lang.String
     * @description
     * @author lemon
     * @date 2020-07-03 15:25
     */
    default String mask(String original, int prefixNoMaskSize, int suffixNoMaskSize) {
        if (StringUtils.isBlank(original)) {
            return original;
        }

        return this.mask(original, prefixNoMaskSize, suffixNoMaskSize, "*");
    }

    /**
     * @param original        原始数据
     * @param prefixNoMaskSize 开始N个字符不脱敏
     * @param suffixNoMaskSize 结尾N个字符不脱敏
     * @param maskFlag        脱敏字符串
     * @return java.lang.String
     * @description
     * @author lemon
     * @date 2020-07-03 14:54
     */
    default String mask(String original, int prefixNoMaskSize, int suffixNoMaskSize, String maskFlag) {
        // 默认脱敏
        if (prefixNoMaskSize == Integer.MIN_VALUE) {
            prefixNoMaskSize = this.getPrefixNoMaskSize();
        }

        if (suffixNoMaskSize == Integer.MIN_VALUE) {
            suffixNoMaskSize = this.getSuffixNoMaskSize();
        }

        // 空或者不需要脱敏
        if (StringUtils.isBlank(original) || (prefixNoMaskSize < 1 && suffixNoMaskSize < 1)) {
            return original;
        }

        if (StringUtils.isBlank(maskFlag)) {
            maskFlag = this.getMaskFlag();
        }

        String left = "";

        if (prefixNoMaskSize >= 1) {
            left = StringUtils.left(original, prefixNoMaskSize);
        }

        String right = "";

        if (suffixNoMaskSize >= 1) {
            right = StringUtils.right(original, suffixNoMaskSize);
        }

        original = StringUtils.rightPad(left, (original.length() - suffixNoMaskSize), maskFlag) + right;

        return original;
    }
}
package com.lemon.mask.strategy;

import com.google.common.collect.Maps;
import com.lemon.mask.annotation.DataMaskType;
import com.lemon.mask.enumeration.SensitiveType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

/**
 * @author lemon
 * @version 1.0
 * @description: 数据脱敏策略
 * @date Create by lemon on 2020-07-06 11:09
 */
@Slf4j
@Component
public class DataMaskStrategyContext implements InitializingBean {
    @Autowired
    private List<DataMaskStrategy> maskStrategys;

    private static final Map<SensitiveType, DataMaskStrategy> MASK_STRATEGY_MAP = Maps.newHashMap();

    @Override
    public void afterPropertiesSet() throws Exception {
        maskStrategys.forEach(maskStrategy -> {
            DataMaskType maskType = maskStrategy.getClass().getAnnotation(DataMaskType.class);

            if (maskType == null) {
                log.error("Class[{}] must specify annotation [{}]", maskStrategy.getClass(), DataMaskType.class);
                return;
            }

            MASK_STRATEGY_MAP.put(maskType.sensitiveType(), maskStrategy);
        });
    }

    /**
     * @param sensitiveType
     * @return com.lemon.mask.strategy.DataMaskStrategy
     * @description 获取数据脱敏策略
     * @author lemon
     * @date 2020-07-06 11:15
     */
    public static DataMaskStrategy getDataMaskStrategy(SensitiveType sensitiveType) {
        return MASK_STRATEGY_MAP.get(sensitiveType);
    }
}
package com.lemon.mask.strategy;

import com.lemon.mask.annotation.DataMaskType;
import com.lemon.mask.enumeration.SensitiveType;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author lemon
 * @version 1.0
 * @description: 默认按照指定前后缀保留不脱敏数据
 * @date Create by lemon on 2020-07-03 14:53
 */
@Getter
@Component
@DataMaskType(sensitiveType = SensitiveType.DEFAULT)
public class DefaultDataMask implements DataMaskStrategy {
    @Value("${mask.prefixNoMaskSize:0}")
    private int prefixNoMaskSize;

    @Value("${mask.suffixNoMaskSize:0}")
    private int suffixNoMaskSize;

    @Value("${mask.maskFlag:*}")
    private String maskFlag;

    /**
     * @param original
     * @return java.lang.String
     * @description [地址] 只显示到地区,不显示详细地址;我们要对个人信息增强保护<例子:北京市海淀区****>
     * @author lemon
     * @date 2020-07-03 14:51
     */
    @Override
    public String mask(String original) {
        if (StringUtils.isBlank(original)) {
            return original;
        }

        return mask(original, prefixNoMaskSize, suffixNoMaskSize, maskFlag);
    }
}
package com.lemon.mask.strategy;

import com.lemon.mask.enumeration.SensitiveType;
import lombok.Data;

/**
 * @author lemon
 * @version 1.0
 * @description: 脱敏配置
 * @date Create by lemon on 2020-07-03 16:38
 */
@Data
public class DesensitizedConfig {
    SensitiveType sensitiveType;

    /**
     * 前置不需要脱敏的长度
     */
    int prefixNoMaskSize;

    /**
     * 后置不需要脱敏的长度
     */
    int suffixNoMaskSize;

    /**
     * 脱敏字符串
     */
    String maskFlag;
}
package com.lemon.mask.strategy;

import com.lemon.mask.annotation.DataMaskType;
import com.lemon.mask.enumeration.SensitiveType;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author lemon
 * @version 1.0
 * @description: [电子邮箱] 邮箱前缀仅显示第一个字母,前缀其他隐藏,用星号代替,@及后面的地址显示<例子:g**@163.com>
 * @date Create by lemon on 2020-07-03 14:53
 */
@Getter
@Component
@DataMaskType(sensitiveType = SensitiveType.EMAIL)
public class Email implements DataMaskStrategy {
    @Value("${mask.prefixNoMaskSize:1}")
    private int prefixNoMaskSize;

    @Value("${mask.suffixNoMaskSize:0}")
    private int suffixNoMaskSize;

    @Value("${mask.maskFlag:*}")
    private String maskFlag;

    /**
     * @param original
     * @return java.lang.String
     * @description [电子邮箱] 邮箱前缀仅显示第一个字母,前缀其他隐藏,用星号代替,@及后面的地址显示<例子:g**@163.com>
     * @author lemon
     * @date 2020-07-03 14:51
     */
    @Override
    public String mask(String original) {
        if (StringUtils.isBlank(original)) {
            return original;
        }

        int index = StringUtils.indexOf(original, "@");

        if (index <= 1) {
            return original;
        } else {
            String temp = mask(original.substring(0, index), prefixNoMaskSize, suffixNoMaskSize, maskFlag);

            if (StringUtils.isBlank(temp)) {
                return original;
            }

            return temp.concat(original.substring(index));
        }
    }
}
package com.lemon.mask.strategy;

import com.lemon.mask.annotation.DataMaskType;
import com.lemon.mask.enumeration.SensitiveType;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author lemon
 * @version 1.0
 * @description: [固定电话] 后四位,其他隐藏<例子:****1234>
 * @date Create by lemon on 2020-07-03 14:53
 */
@Getter
@Component
@DataMaskType(sensitiveType = SensitiveType.FIXED_PHONE)
public class FixedPhone implements DataMaskStrategy {
    @Value("${mask.prefixNoMaskSize:0}")
    private int prefixNoMaskSize;

    @Value("${mask.suffixNoMaskSize:4}")
    private int suffixNoMaskSize;

    @Value("${mask.maskFlag:*}")
    private String maskFlag;

    /**
     * @param original
     * @return java.lang.String
     * @description [固定电话] 后四位,其他隐藏<例子:****1234>
     * @author lemon
     * @date 2020-07-03 14:51
     */
    @Override
    public String mask(String original) {
        if (StringUtils.isBlank(original)) {
            return original;
        }

        return mask(original, prefixNoMaskSize, suffixNoMaskSize, maskFlag);
    }
}
package com.lemon.mask.strategy;

import com.lemon.mask.annotation.DataMaskType;
import com.lemon.mask.enumeration.SensitiveType;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author lemon
 * @version 1.0
 * @description: [身份证号] 显示最后四位,其他隐藏。共计18位或者15位。<例子:*************5762>
 * @date Create by lemon on 2020-07-03 14:53
 */
@Getter
@Component
@DataMaskType(sensitiveType = SensitiveType.ID_CARD)
public class IdCard implements DataMaskStrategy {
    @Value("${mask.prefixNoMaskSize:0}")
    private int prefixNoMaskSize;

    @Value("${mask.suffixNoMaskSize:4}")
    private int suffixNoMaskSize;

    @Value("${mask.maskFlag:*}")
    private String maskFlag;

    /**
     * @param original
     * @return java.lang.String
     * @description [身份证号] 显示最后四位,其他隐藏。共计18位或者15位。<例子:*************5762>
     * @author lemon
     * @date 2020-07-03 14:51
     */
    @Override
    public String mask(String original) {
        if (StringUtils.isBlank(original)) {
            return original;
        }

        return mask(original, prefixNoMaskSize, suffixNoMaskSize, maskFlag);
    }
}

 

package com.lemon.mask.strategy;

import com.lemon.mask.annotation.DataMaskType;
import com.lemon.mask.enumeration.SensitiveType;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author lemon
 * @version 1.0
 * @description: [手机号码] 前三位,后四位,其他隐藏<例子:123******6789>
 * @date Create by lemon on 2020-07-03 14:53
 */
@Getter
@Component
@DataMaskType(sensitiveType = SensitiveType.MOBILE_PHONE)
public class MobilePhone implements DataMaskStrategy {
    @Value("${mask.prefixNoMaskSize:3}")
    private int prefixNoMaskSize;

    @Value("${mask.suffixNoMaskSize:4}")
    private int suffixNoMaskSize;

    @Value("${mask.maskFlag:*}")
    private String maskFlag;

    /**
     * @param original
     * @return java.lang.String
     * @description [手机号码] 前三位,后四位,其他隐藏<例子:123******6789>
     * @author lemon
     * @date 2020-07-03 14:51
     */
    @Override
    public String mask(String original) {
        if (StringUtils.isBlank(original)) {
            return original;
        }

        return mask(original, prefixNoMaskSize, suffixNoMaskSize, maskFlag);
    }
}
package com.lemon.mask.strategy;

import com.lemon.mask.annotation.DataMaskType;
import com.lemon.mask.enumeration.SensitiveType;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author lemon
 * @version 1.0
 * @description: 中文名
 * @date Create by lemon on 2020-07-03 14:53
 */
@Getter
@Component
@DataMaskType(sensitiveType = SensitiveType.PASSWORD)
public class Password implements DataMaskStrategy {
    @Value("${mask.prefixNoMaskSize:0}")
    private int prefixNoMaskSize;

    @Value("${mask.suffixNoMaskSize:0}")
    private int suffixNoMaskSize;

    @Value("${mask.maskFlag:******}")
    private String maskFlag;

    /**
     * @param original
     * @return java.lang.String
     * @description 原始数据脱敏处理
     * @author lemon
     * @date 2020-07-03 14:51
     */
    @Override
    public String mask(String original) {
        if (StringUtils.isBlank(original)) {
            return original;
        }

        return maskFlag;
    }

    /**
     * @param original
     * @param prefixNoMaskSize
     * @param suffixNoMaskSize
     * @param maskFlag
     * @return java.lang.String
     * @description
     * @author lemon
     * @date 2020-07-06 12:27
     */
    @Override
    public String mask(String original, int prefixNoMaskSize, int suffixNoMaskSize, String maskFlag) {
        return this.mask(original);
    }
}
com.lemon.mask.util;
package com.lemon.mask.util;

import com.google.common.base.Preconditions;
import com.lemon.mask.annotation.DataMask;
import com.lemon.mask.strategy.DataMaskStrategy;
import com.lemon.mask.strategy.DataMaskStrategyContext;
import com.lemon.mask.strategy.DesensitizedConfig;
import lombok.extern.slf4j.Slf4j;

/**
 * @author lemon
 * @description 敏感字符串遮罩
 * @date 2020-07-01 19:01
 */
@Slf4j
public class DesensitizedUtils {
    private DesensitizedUtils() {
    }

    /**
     * @param dataMask
     * @return com.lemon.mask.strategy.DesensitizedConfig
     * @description
     * @author lemon
     * @date 2020-07-06 11:21
     */
    public static DesensitizedConfig getDesensitizedConfig(DataMask dataMask) {
        DesensitizedConfig desensitizedConfig = new DesensitizedConfig();
        desensitizedConfig.setSensitiveType(dataMask.sensitiveType());
        desensitizedConfig.setPrefixNoMaskSize(dataMask.prefixNoMaskSize());
        desensitizedConfig.setSuffixNoMaskSize(dataMask.suffixNoMaskSize());
        desensitizedConfig.setMaskFlag(dataMask.maskFlag());

        return desensitizedConfig;
    }

    /**
     * @param original
     * @param desensitizedConfig
     * @return java.lang.String
     * @description 对字符串按指定类型脱敏
     * @author lemon
     * @date 2020-07-03 17:52
     */
    public static String maskValue(String original, DesensitizedConfig desensitizedConfig) {
        Preconditions.checkNotNull(desensitizedConfig.getSensitiveType(), "sensitive type should not be null.");

        DataMaskStrategy maskStrategy = DataMaskStrategyContext.getDataMaskStrategy(desensitizedConfig.getSensitiveType());

        if (maskStrategy == null) {
            log.warn("No matching Mask Strategy found for type [{}]", desensitizedConfig.getSensitiveType());
            return original;
        }

        log.debug("Find MaskStrategy [{}]", maskStrategy.getClass());
        return maskStrategy.mask(desensitizedConfig, original);
    }
}

おすすめ

転載: blog.csdn.net/tgxblue/article/details/108840046