Maison  >  Article  >  Java  >  Comment utiliser la sérialisation Jackson pour réaliser la désensibilisation des données en Java

Comment utiliser la sérialisation Jackson pour réaliser la désensibilisation des données en Java

王林
王林avant
2023-04-18 09:46:10752parcourir

    1.Contexte

    Dans le projet, certaines informations sensibles ne peuvent pas être affichées directement, telles que les numéros de téléphone portable des clients, les cartes d'identité, les numéros de plaque d'immatriculation et d'autres informations. Une désensibilisation des données est requise lors de l'affichage pour éviter les fuites. confidentialité des clients. La désensibilisation consiste à traiter une partie des données avec des symboles de désensibilisation (*).

    2. Objectif

    • Lorsque le serveur renvoie des données, utilisez la sérialisation Jackson pour terminer la désensibilisation des données et obtenir un affichage désensibilisé des informations sensibles.

    • Réduisez le nombre de développements répétés et améliorez l'efficacité du développement

    • Formez des règles de désensibilisation unifiées et efficaces

    • Peut être basé sur la méthode de désensibilisation consistant à remplacer la mise en œuvre de la désensibilisation par défaut pour obtenir des services personnalisés évolutifs et personnalisables Exigences de désensibilisation de la scène

    3. Implémentation principale

    3.1 Implémentation de sérialisation de désensibilisation personnalisée basée sur Jackson

    StdSerializer : La classe de base utilisée par tous les sérialiseurs standard, elle sert à écrire une sérialisation personnalisée. La classe de base recommandée pour une utilisation par les programmes. .

    ContextualSerializer : est une autre interface liée à la sérialisation fournie par Jackson. Sa fonction est de personnaliser JsonSerializer grâce aux informations contextuelles connues par le domaine.

    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);
            }

    Remarque : createContextual peut obtenir le type de champ et les annotations. Lorsqu'un champ a une annotation personnalisée, prenez la valeur dans l'annotation et créez une méthode de sérialisation personnalisée, afin que la valeur puisse être obtenue dans la méthode de sérialisation. La méthode createContextual ne sera appelée que la première fois qu'un champ est sérialisé (car les informations contextuelles du champ ne changeront pas pendant l'exécution), il n'y a donc pas lieu de s'inquiéter des problèmes de performances.

    3.2 Définir l'interface de désensibilisation et l'implémentation en usine

    3.2.1 Définition de l'interface du désensibilisateur

    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 Implémentation de l'usine de désensibilisation

    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 Implémentation du désensibilisateur couramment utilisé

    3.3 .1 Valeur par défaut mise en place de la désensibilisation

    peut être étendu pour mettre en œuvre des scénarios personnalisés basés sur l'implémentation par défaut

    package com.jd.ccmp.ctm.constraints.desensitization;
    
    
    /**
     * 默认脱敏实现
     *
     * @author zhangxiaoxu15
     * @date 2022/2/8 11:01
     */
    public interface DefaultDesensitization extends Desensitization<String> {
    }

    3.3.2 Désensibilisateur de numéro de téléphone portable

    réalise la désensibilisation des 4 chiffres du milieu du numéro de téléphone mobile

    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 Définition des annotations

    Implémenter des annotations personnalisées via @JacksonAnnotationsInside pour améliorer la facilité d'utilisation

    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 Annotation de désensibilisation par défaut

    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 Annotation de désensibilisation du numéro de téléphone portable

    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 Définir des symboles de désensibilisation

    Supporté Spécifier des symboles de désensibilisation, tels que * ou ^_^

    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. Exemples d'utilisation et analyse du processus d'exécution

    Comment utiliser la sérialisation Jackson pour réaliser la désensibilisation des données en Java

    Diagramme des classes de programme

    Comment utiliser la sérialisation Jackson pour réaliser la désensibilisation des données en Java

    **Analyse du processus d'exécution**

    1. Appelez JsonUtil.toJsonString() pour démarrer la sérialisation

    2. Identifiez l'annotation @MobileNoDesensitize sur l'attribut mobile (3.4.2 ci-dessus)

    3. Appelez ObjectDesensitizeSerializer#createContextual (3.1 & 3.2 ci-dessus) et renvoyez JsonSerializer

    4. Appelez la désensibilisation du numéro de téléphone mobile pour implémenter MobileNoDesensitization#desensitize (3.3.2 ci-dessus)

    5. Sortez le résultat de la sérialisation désensibilisée, {"mobile": "133****5678"}

    Il n'est pas difficile de trouver le noyau Le processus d'exécution est l'étape 3, mais comment sont @MobileNoDesensitize et ObjectDesensitizeSerializer connectés ?

    • Essayez de trier les liens de référence : @MobileNoDesensitize -> @Desensitize -> @JsonSerialize -> ObjectDesensitizeSerializer

    • Cependant, dans l'implémentation d'ObjectDesensitizeSerializer, nous ne semblons pas trouver d'appels directs au liens ci-dessus Relation

    • Il faut dire cela du concept de méta-annotations de 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
    {
    }

    C'est à travers le mécanisme des "combo-annotations" (annotations combinées, annotations groupées) qui demande à Jackson d'utiliser la méta -annotations qu'il possède, au lieu d'utiliser des annotations cibles, permettant une désensibilisation personnalisée pour atteindre les objectifs de conception.

    Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

    Déclaration:
    Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer