2016-07-15 7 views
1

Ich habe bestimmte Felder bestimmter Objekte, die, wenn für die Speicherung in DB serialisiert werden, müssen verschlüsselt werden.Java Jackson Custom Polymorphc Deserializer zum Verschlüsseln/Entschlüsseln von Feldern

Sie müssen nicht im Speicher verschlüsselt werden. Ich möchte dies auf transparente Weise für den Rest der Codebasis erreichen, also dachte ich mir, den enc/dec-Schritt auf die ser/deser-Ebene zu setzen.

Um generisch zu sein, ich habe eine Schnittstelle und eine Anmerkung erstellt:

@JsonTypeInfo(
     use = JsonTypeInfo.Id.NAME, 
     include = JsonTypeInfo.As.PROPERTY, 
     property = "__TYPE__") 
@JsonSubTypes({ 
     @JsonSubTypes.Type(value = Type1.class, name = "Type1"), 
     @JsonSubTypes.Type(value = Type2.class, name = "Type2"), 
     @JsonSubTypes.Type(value = Type3.class, name = "Type3") 
}) 

@JsonSerialize(using=EncryptedSerializer.class) 
@JsonDeserialize(using=EncryptedDeserializer.class) 
public interface EncryptedType {} 

und

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

Die Idee ist, dass die Klassen werden die leere Schnittstelle implementieren, um einen gelegt werden, custom ser/deser, der reflektiv die Felder findet und magisch wirkt, wenn sie kommentiert sind. Die Serialisierung Schritt wirkt wie ein Zauber, und ich erhalte eine Ausgabezeichenfolge wie: {“TYPE ":" Typ1" , "encryptedField": "aGAzLwT47gE/QNlUuAhnJg ==", "unencryptedField": "Klartext"}

Aber die Entschlüsselung ist schrecklich. Ich kann es nicht funktionieren lassen: Ich bin nicht sicher, welche Dinge zu implementieren, um den Polymorphismus UND die Entschlüsselung zu kombinieren.

Wenn ich die @ JsonDeserialize-Annotation entferne und Jackson seine Sache machen lasse, dann deserialisiert es polymorph korrekt, aber mit den verschlüsselten Feldern. Wenn ich versuche, meinen benutzerdefinierten Deserializer zu verwenden, erhalte ich alle möglichen Fehler von NPE bis Jackson. Was ich in meinem Deserializer erreichen will, ist so etwas wie:

  1. Jackson, dieses Ding deserialisieren, wie Sie wissen, wie die Art Informationen mit den verschlüsselten Feldern
  2. vor der Rückkehr, lassen Sie mich auf der Instanz meine Entschlüsselung tun (muss nicht richtig eingegeben werden, ich kann durch Reflexion zugreifen). Hier

ist das, was ich bisher:

public class EncryptedDeserializer extends StdDeserializer<EncryptedType> { 
[..super etc..] 


@Override 
public EncryptedType deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { 
    return null; 
} 

@Override 
public EncryptedType deserializeWithType(JsonParser p, DeserializationContext ctxt, 
     TypeDeserializer typeDeserializer) throws IOException { 
    EncryptedType newInstance = super.deserializeWithType(p, ctxt, typeDeserializer); 

    Field[] fields = newInstance.getClass().getDeclaredFields(); 
    for (Field field : fields) { 
     if (field.isAnnotationPresent(EncryptedField.class)) { 
      boolean accessibility = field.isAccessible(); 
      field.setAccessible(true); 
      try { 
       field.set(newInstance, ApplicationContextRegister.getApplicationContext().getBean(TextEncryptionService.class).decrypt((String) field.get(newInstance))); 
      } catch (Exception e) { 
       log.error("Could not decryption field " + field.getName() + " of " + newInstance + ". Skipping decryption"); 
      } 
      field.setAccessible(accessibility); 
     } 
    } 
    return newInstance; 
} 

Aber dies nicht mit Fehlern oder über EncryptedDeserializer beschwert hat keinen Standard (kein arg) Konstruktor oder ich habe wirklich verschiedene Möglichkeiten ausprobiert, aber ich erhalte immer stecken.

+0

jackson-crypto auf github tut dies, aber erzeugt ein bisschen anders Ausgabe. Es verwendet Bean-Serialisierungsmodifikatoren, um andere (De-) Serialisierer zu umbrechen. Den Code dafür finden Sie [hier] (https://github.com/meltmedia/jackson-crypto/tree/develop/src/main/java/com/meltmedia/jackson/crypto). –

Antwort

0

Sie benötigen die @JsonTypeInfo Zeug für Polymorphie, wie Sie abgeleitet haben.

Ein benutzerdefinierter Deserializer ist eine Möglichkeit, Ihre Verschlüsselungslogik zu erreichen. Wenn Sie wollten, könnten Sie immer eine @JsonCreator Annotation auf Ihrem Konstruktor für die Deserialisierung versuchen (und die Entschlüsselungslogik darin einschließen) und die Verschlüsselung durch Annotationen auf kundenspezifischen Gettern behandeln lassen.

In Bezug auf den spezifischen Fehler von "EncryptedDeserializer hat keinen Standard (kein Arg) -Konstruktor" - warum nicht einfach einen erstellen (auch wenn es private ist)? Jackson benutzt solche Dinge zur Instantiierung durch Reflexion.

+0

Können Sie vielleicht ein Beispiel dafür geben, wie Sie einen benutzerdefinierten polymorphen Deserializer (keine Dekrettierung) implementieren können? Die technische Art, das zu tun, ist das, was mich beschäftigt, nicht die Entschlüsselung.Das Problem mit dem Konstruktor ist nur eines der vielen Dinge, die ich versucht habe und die ich nicht erreichen konnte. Ich weiß, wie man es dort hinstellt, aber es wird immer noch nicht funktionieren. Ich bin mir nicht bewusst, wie polymorphe benutzerdefinierte Deserialisierer gemacht werden, und das ist, was mich stopt –

+0

Wie https://fasterxml.github.io/jackson-databind/javadoc/2.2.0/com/fasterxml/jackson/databind/annotation /JsonDeserialize.html, '@ JsonDeserialize' ist" Anmerkung, die zum Konfigurieren von Deserialisierungsaspekten verwendet wird, indem sie an "Setter" -Methoden oder -Felder angefügt oder an Wertklassen ". Ich glaube nicht, dass Sie es direkt auf eine Schnittstelle anwenden können, obwohl Sie in der Lage sein sollten, es auf eine abstrakte Klasse anzuwenden. Ich werde versuchen, ein funktionierendes Beispiel zu finden, bereitstehen. – Olaf

Verwandte Themen