顧客の携帯電話番号、ID カード、ナンバー プレート番号など、プロジェクト内の一部の機密情報は直接表示できません。顧客のプライバシーの漏洩を防ぐために、データの機密保護を解除する必要があります。非感作とは、データの一部を非感作シンボル (*) で処理することです。
サーバーがデータを返すときに、Jackson シリアル化を使用してデータの匿名化を完了し、機密情報の匿名化された表示を実現します。
ContextualSerializer:
は、Jackson によって提供されるもう 1 つのシリアル化関連のインターフェイスであり、その機能は、フィールドによって既知のコンテキスト情報を通じて JsonSerializer をカスタマイズすることです。package com.jd.ccmp.ctm.constraints.serializer; 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.ContextualSerializer; import com.fasterxml.jackson.databind.ser.std.StdSerializer; import com.jd.ccmp.ctm.constraints.Symbol; import com.jd.ccmp.ctm.constraints.annotation.Desensitize; import com.jd.ccmp.ctm.constraints.desensitization.Desensitization; import com.jd.ccmp.ctm.constraints.desensitization.DesensitizationFactory; import com.jd.ccmp.ctm.constraints.desensitization.DefaultDesensitization; import java.io.IOException; /** * 脱敏序列化器 * * @author zhangxiaoxu15 * @date 2022/2/8 11:10 */ public class ObjectDesensitizeSerializer extends StdSerializer<Object> implements ContextualSerializer { private static final long serialVersionUID = -7868746622368564541L; private transient Desensitization<Object> desensitization; protected ObjectDesensitizeSerializer() { super(Object.class); } public Desensitization<Object> 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 != DefaultDesensitization.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); }注: createContextual はフィールド タイプと注釈を取得できます。フィールドにカスタム アノテーションがある場合、アノテーションの値を取得し、カスタマイズされたシリアル化メソッドを作成して、シリアル化メソッドで値を取得できるようにします。 createContextual メソッドは、フィールドが初めてシリアル化されるときにのみ呼び出されます (フィールドのコンテキスト情報は実行時に変更されないため)。そのため、パフォーマンスの問題を心配する必要はありません。
3.2 感度解除インターフェイスとファクトリ実装の定義
package com.jd.ccmp.ctm.constraints.desensitization; /** * 脱敏器 * * @author zhangxiaoxu15 * @date 2022/2/8 10:56 */ public interface Desensitization<T> { /** * 脱敏实现 * * @param target 脱敏对象 * @return 脱敏返回结果 */ T desensitize(T target); }3.2.2 感度解除デバイスのファクトリ実装
package com.jd.ccmp.ctm.constraints.desensitization; import java.util.HashMap; import java.util.Map; /** * 工厂方法 * * @author zhangxiaoxu15 * @date 2022/2/8 10:58 */ public class DesensitizationFactory { private DesensitizationFactory() { } private static final Map<Class<?>, Desensitization<?>> map = new HashMap<>(); @SuppressWarnings("all") public static Desensitization<?> getDesensitization(Class<?> clazz) { if (clazz.isInterface()) { throw new UnsupportedOperationException("desensitization is interface, what is expected is an implementation class !"); } return map.computeIfAbsent(clazz, key -> { try { return (Desensitization<?>) clazz.newInstance(); } catch (InstantiationException | IllegalAccessException e) { throw new UnsupportedOperationException(e.getMessage(), e); } });3.3 一般的に使用される感度解除の実装
はデフォルトの実装に基づくことができ、パーソナライズされたシナリオの実装を拡張できます
package com.jd.ccmp.ctm.constraints.desensitization; /** * 默认脱敏实现 * * @author zhangxiaoxu15 * @date 2022/2/8 11:01 */ public interface DefaultDesensitization extends Desensitization<String> { }
3.3.2 携帯電話番号のセンシタイザ
携帯電話番号の中間の 4 桁のセンシタイズを実現
package com.jd.ccmp.ctm.constraints.desensitization; import com.jd.ccmp.ctm.constraints.Symbol; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * 手机号脱敏器,保留前3位和后4位 * * @author zhangxiaoxu15 * @date 2022/2/8 11:02 */ public class MobileNoDesensitization implements DefaultDesensitization { /** * 手机号正则 */ 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}"); @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;3.4 アノテーションの定義 使いやすさを向上させるために、@JacksonAnnotationsInside を通じてカスタム アノテーションを実装します。
package com.jd.ccmp.ctm.constraints.annotation; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.jd.ccmp.ctm.constraints.desensitization.Desensitization; import com.jd.ccmp.ctm.constraints.serializer.ObjectDesensitizeSerializer; import java.lang.annotation.*; /** * 脱敏注解 * * @author zhangxiaoxu15 * @date 2022/2/8 11:09 */ @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.4.1 デフォルトの感度解除アノテーション
package com.jd.ccmp.ctm.constraints.annotation; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; import com.jd.ccmp.ctm.constraints.desensitization.DefaultDesensitization; import java.lang.annotation.*; /** * 默认脱敏注解 * * @author zhangxiaoxu15 * @date 2022/2/8 11:14 */ @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotationsInside @Desensitize(desensitization = DefaultDesensitization.class) @Documented public @interface DefaultDesensitize {3.4.2 携帯電話番号感度解除アノテーション
package com.jd.ccmp.ctm.constraints.annotation; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; import com.jd.ccmp.ctm.constraints.desensitization.MobileNoDesensitization; import java.lang.annotation.*; /** * 手机号脱敏 * * @author zhangxiaoxu15 * @date 2022/2/8 11:18 */ @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotationsInside @Desensitize(desensitization = MobileNoDesensitization.class) @Documented public @interface MobileNoDesensitize { }3.5 感度解除シンボルの定義 は、* や ^_^
package com.jd.ccmp.ctm.constraints; import java.util.stream.Collectors; import java.util.stream.IntStream; /** * 脱敏符号 * * @author zhangxiaoxu15 * @date 2022/2/8 10:53 */ public class Symbol { /** * '*'脱敏符 */ public static final String STAR = "*"; private Symbol() {} /** * 获取符号 * * @param number 符号个数 * @param symbol 符号 */ public static String getSymbol(int number, String symbol) { return IntStream.range(0, number).mapToObj(i -> symbol).collect(Collectors.joining()); }
#プログラム クラス図
##**実行プロセスの分析**
1. JsonUtil.toJsonString() を呼び出してシリアル化を開始します
2. 属性 mobile## の注釈 @MobileNoDesensitize (上記の 3.4.2) を特定します # 3. ObjectDesensitizeSerializer#createContextual (3.1 & 3.2 (上記))、JsonSerializer
4. 携帯電話番号に電話して感度を解除します。 MobileNoDesensitization#desensitize (上記 3.3.2)
5. 出力 感度を解除した後のシリアル化結果、{"mobile": "133****5678"}
コアの実行プロセスがステップ 3 であることを見つけるのは難しくありませんが、@MobileNoDesensitize と ObjectDesensitizeSerializer はどのように接続されていますか? 毛織物?
参照リンクを整理してみてください: @MobileNoDesensitize -> @Desensitize -> @JsonSerialize -> ObjectDesensitizeSerializer
//**Jackson元注解** //1.提到元注解这个词,大家会想到@Target、@Retention、@Documented、@Inherited //2.Jackson也以同样的思路设计了@JacksonAnnotationsInside /** * Meta-annotation (annotations used on other annotations) * used for indicating that instead of using target annotation * (annotation annotated with this annotation), * Jackson should use meta-annotations it has. * This can be useful in creating "combo-annotations" by having * a container annotation, which needs to be annotated with this * annotation as well as all annotations it 'contains'. * * @since 2.0 */ @Target({ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotation public @interface JacksonAnnotationsInside { }「コンボ アノテーション」(結合されたアノテーション、バンドルされたアノテーション) のメカニズムを通じて、ターゲット アノテーションを使用する代わりに独自のメタ アノテーションを使用するように Jackson に指示することができ、それによってカスタムの感度解除を実現できます。設計目標を達成するために。
以上がJackson シリアル化を使用して Java でデータの非感作を実現する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。