[Spring] Obfusquer des champs spécifiques à l'aide d'annotations [Java]

Si vous utilisez l'ID qui est automatiquement numéroté dans la base de données comme pour l'ID affiché à l'écran, l'utilisateur devinera diverses choses. (Cela s'appelle le nombre d'utilisateurs)

Pour un champ aussi spécial, je pense qu'il est courant de préparer un objet de valeur dédié et d'écrire le processus de conversion d'identifiant en interne. Cependant, lorsque le type de demande ou de modèle de réponse ne peut pas être modifié en raison de circonstances complexes, j'ai cherché à savoir s'il pouvait être géré avec des annotations.

L'environnement de travail est Java9,SpringBoot (2.0.0.RELEASE). (Je n'ai rien fait de spécial, donc je pense que les autres versions sont bien)

Exigences

Les exigences pour ce temps sont les suivantes.

spécification

Sur la base des exigences ci-dessus, je voudrais faire les spécifications comme suit.

--Annotation est ʻObfusquer`

la mise en oeuvre

Sérialiseur

Cette classe est obscurcie. (Où quitter le serveur) Héritez et implémentez StdSerializer. S'il est «nul», il se terminera tel quel. (Parce que NotNull etc. doit être exprimé par d'autres annotations)

ObfuscateSerializer.java


public class ObfuscateSerializer extends StdSerializer<Long> {

    private static final long serialVersionUID = -6910413385029615313L;

    protected ObfuscateSerializer() {
        super(Long.class);
    }

    @Override
    public void serialize(Long value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        //Logique d'obfuscation
        if (value == null) {
            return;
        }
        gen.writeNumber(value + 1);
    }
    
}

Désérialiseur

C'est une classe qui simplifie. (Où entrer dans le serveur) Comme le sérialiseur, il utilise StdDeserializer.

ObfuscateDeserializer.java


public class ObfuscateDeserializer extends StdDeserializer<Long> {

    private static final long serialVersionUID = 4303388430635458159L;

    protected ObfuscateDeserializer() {
        super(Long.class);
    }

    @Override
    public Long deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        //Logique simplifiée
        return Long.parseLong(p.getValueAsString()) - 1;
    }

}
{
"timestamp": 1521424385168,
"status": 400,
"error": "Bad Request",
"message": "JSON parse error: For input string: \"hoge\"; nested exception is com.fasterxml.jackson.databind.JsonMappingException: For input string: \"hoge\" (through reference chain: com.example.Hoge[\"value\"])",
"path": "/api/sample/obfuscate"
}

Annotation

Puisqu'il s'agit d'une annotation de marqueur, elle n'a aucune propriété. La cible est définie uniquement sur ʻElementType.FIELD` dans les spécifications.

Obfuscate.java


@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD })
public @interface Obfuscate { 
}

Intercepteur d'annotation

C'est une classe qui associe l'annotation définie au sérialiseur / désérialiseur. Héritez et implémentez JacksonAnnotationIntrospector. Cette classe est appelée pour chaque élément lorsque Jackson dans Spring Boot convertit json en classe spécifiée et que la classe, le champ ou la méthode cible est annoté. Cette fois, nous rendrons le sérialiseur et le désérialiseur uniques, donc nous remplacerons les paramètres findSerializer et findDeserializer.

MyAnnotationInterceptor.java


public class MyAnnotationInterceptor extends JacksonAnnotationIntrospector {

    private static final long serialVersionUID = -7722925738908936096L;

    @Override
    public Object findSerializer(Annotated a) {
        if (a.hasAnnotation(Obfuscate.class)) {
            return ObfuscateSerializer.class;
        }
        return super.findSerializer(a);
    }

    @Override
    public Object findDeserializer(Annotated a) {
        if (a.hasAnnotation(Obfuscate.class)) {
            return ObfuscateDeserializer.class;
        }
        return super.findDeserializer(a);
    }

}

Config

Enregistrez l'intercepteur d'annotations ci-dessus avec Spring Boot.

JacksonConfig.java


@Configuration
public class JacksonConfig {

    @Bean
    public Jackson2ObjectMapperBuilder jacksonBuilder() {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
        builder.annotationIntrospector(new MyAnnotationInterceptor());
        return builder;
    }

}

Exemple d'utilisation

Maintenant que vous êtes prêt, vous pouvez ajouter @ Obfuscate aux champs du modèle de demande ou de réponse et ils seront convertis automatiquement.

ObfuscateRequest.java


@lombok.Value
public class ObfuscateRequest {
    
    @Obfuscate
    Long id;

}

Résumé

Cette fois, j'ai défini une annotation pour obscurcir et simplifier le champ. Je pense qu'il y a des situations où il est utile s'il a déjà été publié et qu'il est difficile de changer de classe, ou si vous réutilisez le modèle et ne pouvez pas le changer. De plus, dans le cas des objets de valeur, il y a quelques inconvénients (bien que cela puisse être évité) tels que l'approfondissement de la hiérarchie lors de l'utilisation de json, donc j'ai pensé que c'était un bon choix.

référence

https://qiita.com/nijuya_o/items/0f512792c4db27913c7a https://qiita.com/k_ui/items/b6e1763d023da96ea46f

Recommended Posts

[Spring] Obfusquer des champs spécifiques à l'aide d'annotations [Java]
Utilisation de Mapper avec Java (Spring)
Spring Java
Injection de dépendances Spring à l'aide de Java, Kotlin
[Java] Spring DI ③
Tri à l'aide du comparateur java
Pratique de grattage avec Java ②
Pratique du grattage avec Java ①
Consultez les annotations Java maintenant
Essayez d'utiliser Spring JDBC