Java利用Jackson序列化實現資料脫敏
阿新 • • 發佈:2021-10-14
幾天前使用了Jackson對資料的自定義序列化。突發靈感,利用此方法來簡單實現介面返回資料脫敏,故寫此文記錄。
核心思想是利用Jackson的StdSerializer
,@onSerialize
,以及自己實現的資料脫敏過程。
使用效果如下:
首先在需要進行脫敏的VO欄位上面標註相關脫敏註解
呼叫介面即可看到脫敏效果
實現過程如下:
1. 定義脫敏的過程實現
/** * Created by EalenXie on 2021/9/24 15:52 * 頂級的脫敏器 */ public interface Desensitization<T> { /** * 脫敏實現 * * @param target 脫敏物件 * @return 脫敏返回結果 */ T desensitize(T target); }
比如具體的手機號脫敏器實現
import com..Symbol; import .util.regex.Matcher; import java.util.regex.Pattern; /** * Created by EalenXie on 2021/9/24 15:56 * 手機號脫敏器 預設只保留前3位和後4位 */ public class PhoneDesensitization implements StringDesensitization { /** * 手機號正則 */ private static final Pattern DEFAULT_PATTERN = Pattern.compile("(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\d{8}"); /** * 手機號脫敏 只保留前3位和後4位 */ @Override public String desensitize(String target) { Matcher matcher = DEFAULT_PATTERN.matcher(target); while (matcher.find()) { String group = matcher.group(); target = target.replace(group,group.substring(0,3) + Symbol.getSymbol(4,Symbol.STAR) + group.substring(7,11)); } return target; } }
2.定義脫敏註解,並指明瞭使用的序列化器,註解中聲明瞭使用的脫敏器實現
package com.github.annotation; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.github.desensitization.Desensitization; import com.github.serializer.ObjectDesensitizeSerializer; import java.lang.annotation.*; /** * Created by EalenXie on 20GcdIfdj21/10/8 11:30 */ @Target({ElementType.FIELD,ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotationsInside @JsonSerialize(using = ObjectDesensitizeSerializer.class) @Documented public @interface Desensitize { /** * 脫敏器實現 */ @SuppressWarnings("all") Class<? extends Desensitization<?>> desensitization(); }
3. 實現定義的序列化器
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.Cwww.cppcns.comontextualSerializer;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.github.Symbol;
import com.github.annotation.Desensitize;
import com.github.desensitization.Desensitization;
import com.github.desensitization.DesensitizationFactory;
import com.github.desensitization.StringDesensitization;
import java.io.IOException;
/**
* Created by EalenXie on 2021/8/9 9:03
* 脫敏序列化器
*/
public class ObjectDesensitizeSerializer extends StdSerializer<Object> implements ContextualSerializer {
private transient Desensitization<Object> desensitization;
protected ObjectDesensitizeSerializer() {
super(Object.class);
}
public Desensitization<Object&GcdIfdjgt; getDesensitization() {
return desensitization;
}
public void setDesensitization(Desensitization<Object> desensitization) {
this.desensitization = desensitization;
}
@Override
public JsonSerializer<Object> createContextual(SerializerProvider prov,BeanProperty property) {
Desensitize annotation = property.getAnnotation(Desensitize.class);
return createContextual(annotation.desensitization());
}
@SuppressWarnings("unchecked")
public JsonSerializer<Object> createContextual(Class<? extends Desensitization<?>> clazz) {
ObjectDesensitizeSerializer serializer = new ObjectDesensitizeSerializer();
if (clazz != StringDesensitization.class) {
serializer.setDesensitization((Desensitization<Object>) DesensitizationFactory.getDesensitization(clazz));
}
return serializer;
}
@Override
public void serialize(Object value,JsonGenerator gen,SerializerProvider provider) throws IOException {
Desensitization<Object> objectDesensitization = getDesensitization();
if (objectDesensitization != null) {
try {
gen.writeObject(objectDesensitization.desensitize(value));
} catch (Exception e) {
gen.writeObject(value);
}
} else if (value instanceof String) {
gen.writeString(Symbol.getSymbol(((String) value).length(),Symbol.STAR));
} else {
gen.writeObject(value);
}
}
}
4.程式碼的設計說明
完整程式碼可見 : https://github.com/EalenXie/jackson-desensitize
另附 基於Logback的日誌脫敏方案(筆者認為這可能是全網最簡單快捷的)
原理是利用Logback的自定義日誌轉換器ClassicConverter
1. 自定義脫敏日誌轉換器
import ch.qos.logback.classic.pattern.ClassicConverter; import ch.qos.logback.classic.spi.ILoggingEvent; import com.github.desensitization.EmailDesensitization; import com.github.desensitization.IDCardDesensitization; import com.github.desensitization.PhoneDesensitization; import com.github.desensitization.StringDesensitization; import java.util.ArrayList; import java.util.List; /** * @author EalenXie create on 2021/3/18 10:07 * 此Converter提供支援日誌脫敏 * 1. 編寫此LogbackDesensitizeConverter * 2. 正則脫敏 手機號/郵箱/身份證 */ public class LogbackDesensitizeConverter extends ClassicConverter { protected static final List<StringDesensitization> DESENSITIZATION_LIST = new ArrayList<>(); static { // 手機號脫敏 DESENSITIZATION_LIST.add(new PhoneDesensitization()); // 郵箱脫敏 DESENSITIZATION_LIST.add(new EmailDesensitization()); // 身份證脫敏 DESENSITIZATION_LIST.add(new IDCardDesensitization()); } @Override public String convert(ILoggingEvent event) { String content = event.getMessage(); try { for (StringDesensitization desensitization : DESENSITIZATION_LIST) { content = desensitization.desensitize(content); } } catch (Exception e) { // ig } return content; } }
2. 啟動類為PatternLayout
的靜態變數defaultConverterMap
新增此自定義轉換器
import ch.qos.logback.classic.PatternLayout; import com.github.filter.LogbackDesensitizeConverter; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; /** * @author EalenXie create on 2020/11/24 14:16 */ @EnableDiscoveryClient @SpringBootApplication public class ApiGatewayApplication { public static void main(String[] args) { // 日誌處理方案 新增一個Logback的日誌脫敏轉換器 PatternLayout.defaultConverterMap.put("m",LogbackDesensitizeConverter.class.getName()); SpringApplication.run(ApiGatewayApplication.class,args); } }
啟動後可以看到日誌脫敏效果。
到此這篇關於利用Jackson序列化實現資料脫敏的文章就介紹到這了,更多相關Jackson序列化資料脫敏內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!