ホームページ  >  記事  >  Java  >  Jackson シリアル化を使用して Java でデータの非感作を実現する方法

Jackson シリアル化を使用して Java でデータの非感作を実現する方法

王林
王林転載
2023-04-18 09:46:10752ブラウズ

    1. 背景

    顧客の携帯電話番号、ID カード、ナンバー プレート番号など、プロジェクト内の一部の機密情報は直接表示できません。顧客のプライバシーの漏洩を防ぐために、データの機密保護を解除する必要があります。非感作とは、データの一部を非感作シンボル (*) で処理することです。

    2. 目標

    • サーバーがデータを返すときに、Jackson シリアル化を使用してデータの匿名化を完了し、機密情報の匿名化された表示を実現します。

    • #繰り返しの開発量を削減し、開発効率を向上させます

    • #統合された効果的な非感作ルールを作成します

    • これは、デフォルトの非感作実装をオーバーライドする非感作メソッドに基づいて、スケーラブルでカスタマイズ可能なパーソナライズされたビジネス シナリオの非感作要件を実現できます

    • #3. メインの実装
    # 3.1 Jackson

    StdSerializer

    に基づくカスタムの感度を下げたシリアル化の実装: すべての標準シリアライザーで使用される基本クラスで、カスタム シリアライザーを作成する場合に推奨されるベースです。

    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 感度解除インターフェイスとファクトリ実装の定義

    3.2.1 感度解除インターフェイスの定義

    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 一般的に使用される感度解除の実装

    3.3.1デフォルトの感度解除実装

    はデフォルトの実装に基づくことができ、パーソナライズされたシナリオの実装を拡張できます

    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 {
        /**
         * &#39;*&#39;脱敏符
         */
        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());
        }

    4 などの指定された感度解除シンボルをサポートします。使用例サンプルと実行プロセスの分析

    #プログラム クラス図Jackson シリアル化を使用して Java でデータの非感作を実現する方法

    ##**実行プロセスの分析**

    1. JsonUtil.toJsonString() を呼び出してシリアル化を開始しますJackson シリアル化を使用して Java でデータの非感作を実現する方法

    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

      ただし、 ObjectDesensitizeSerializer の実装では、上記のリンクの直接呼び出し関係が見つからなかったようです
    • #これは Jackson メタアノテーションの概念について説明する必要があります
    • //**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 &#39;contains&#39;.
       * 
       * @since 2.0
       */
      @Target({ElementType.ANNOTATION_TYPE})
      @Retention(RetentionPolicy.RUNTIME)
      @JacksonAnnotation
      public @interface JacksonAnnotationsInside
      {
      }

      「コンボ アノテーション」(結合されたアノテーション、バンドルされたアノテーション) のメカニズムを通じて、ターゲット アノテーションを使用する代わりに独自のメタ アノテーションを使用するように Jackson に指示することができ、それによってカスタムの感度解除を実現できます。設計目標を達成するために。

    以上がJackson シリアル化を使用して Java でデータの非感作を実現する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    声明:
    この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。