1. 程式人生 > >用spring標籤實現欄位的脫敏

用spring標籤實現欄位的脫敏

問題描述

在springboot中實現資料庫脫敏,可以選擇在物件序列化之前進行處理脫敏,接下來就是具體的操作了。(參考了網上的資料進行了整理)

解決方案

第一步

構建列舉類,用來識別每個脫敏欄位

/**
 * @author tori
 * 2018/7/16 上午11:19
 */
public enum SensitiveType {
    /** 手機號 */
    MOBILE,

    /** 電子郵箱 */
    EMAIL,

    /** openId */
    OPEN_ID
}

第二步

建立處理脫敏欄位的工具類(這裡只展示了mobile,其他類推)

/**
 * @author
tori * 2018/7/16 下午1:57 */
public class SensitiveUtil { public static String mobile(String mobile) { if (StringUtils.isBlank(mobile)) { return ""; } return StringUtils.left(mobile, 2).concat( StringUtils.removeStart( StringUtils.leftPad( StringUtils.right(mobile, 4
), StringUtils.length(mobile), "*"), "***")); } }

第三步

建立標籤類(構建標籤)

/**
 * @author tori
 * 2018/7/16 上午11:33
 */

//@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = SensitiveInfoSerialize.class)
public
@interface SensitiveInfo { SensitiveType value(); }

有時在寫標籤類時會碰到@Target,@Retention還有@Order的用法,這裡簡單的概括一下:

@Target

這個註解就是表明該註解類能夠作用的範圍,也就是能夠註解在哪,比如 類、方法、引數等。 
下面是他的一些引數: 
@Target(ElementType.TYPE) //介面、類、列舉、註解 
@Target(ElementType.FIELD) //欄位、列舉的常量 
@Target(ElementType.METHOD) //方法 
@Target(ElementType.PARAMETER) //方法引數 
@Target(ElementType.CONSTRUCTOR) //建構函式 
@Target(ElementType.LOCAL_VARIABLE)//區域性變數 
@Target(ElementType.ANNOTATION_TYPE)//註解 
@Target(ElementType.PACKAGE) ///包 
裡面的引數是可以多選的,使用方法比如@Target({ElementType.METHOD,ElementType.TYPE})。

@Retention

這個註解是保留說明,也就是表明這個註解所註解的類能在哪裡保留,他有三個屬性值: 
RetentionPolicy.SOURCE —— 這種型別的Annotations只在原始碼級別保留,編譯時就會被忽略 
RetentionPolicy.CLASS —— 這種型別的Annotations編譯時被保留,在class檔案中存在,但JVM將會忽略 
RetentionPolicy.RUNTIME —— 這種型別的Annotations將被JVM保留,所以他們能在執行時被JVM或其他使用反射機制的程式碼所讀取和使用。 
從上面可以看出一般使用的事第三個屬性,其餘兩個屬性,說實話 我也不清楚什麼情況下使用這兩種。

@Order

@Order標記定義了元件的載入順序,這個標記包含一個value屬性。屬性接受整形值。如:1,2 等等。值越小擁有越高的優先順序。Ordered.HIGHEST_PRECEDENCE這個屬性值是最高優先順序的屬性,它的值是-2147483648,對應的最低屬性值是Ordered.LOWEST_PRECEDENCE,它的值是2147483647

第四步

最重要的標籤序列化處理類:

/**
 * @author tori
 * 2018/7/16 下午1:33
 */
public class SensitiveInfoSerialize extends JsonSerializer<String> implements ContextualSerializer {

    private SensitiveType type;

    public SensitiveInfoSerialize(SensitiveType type) {
        this.type = type;
    }

    public SensitiveInfoSerialize() {}

    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
        switch (this.type) {
            case MOBILE:
                gen.writeString(SensitiveUtil.mobile(value));
                break;
            case EMAIL:
                gen.writeString(SensitiveUtil.email(value));
                break;
            case OPEN_ID:
                gen.writeString(SensitiveUtil.openId(value));
                break;
        }
    }

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
        if (property != null) { // 為空直接跳過
            if (Objects.equals(property.getType().getRawClass(), String.class)) { // 非 String 類直接跳過
                SensitiveInfo sensitiveInfo = property.getAnnotation(SensitiveInfo.class);
                if (sensitiveInfo == null) {
                    sensitiveInfo = property.getContextAnnotation(SensitiveInfo.class);
                }
                if (sensitiveInfo != null) { // 如果能得到註解,就將註解的 value 傳入 SensitiveInfoSerialize

                    return new SensitiveInfoSerialize(sensitiveInfo.value());
                }
            }
            return prov.findValueSerializer(property.getType(), property);
        }
        return prov.findNullValueSerializer(property);
    }
}

最後一步

就是使用和測試啦:

 /**
  * 手機號碼
  */
@SensitiveInfo(SensitiveType.MOBILE)
private String mobile;

這樣一來獲得的json中mobile,email,openId就可以隱藏部分內容,實現脫敏了。

以上是對spring標籤實現脫敏的流程描述。☺