【问题标题】:Java Jackson Custom Polymorphc Deserializer to encrypt/decrypt fieldsJava Jackson Custom Polymorphc Deserializer 用于加密/解密字段
【发布时间】:2016-07-15 09:05:45
【问题描述】:

我有某些对象的某些字段,当序列化以存储在 DB 中时,需要加密。

它们在内存中不需要被加密。我想以对代码库的其余部分透明的方式实现这一点,所以我想将 enc/dec 步骤放在 ser/deser 级别。

为了通用,我创建了一个接口和一个注解:

@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 {}

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

这个想法是,这些类将实现空接口以匹配自定义的 ser/deser,它反射性地查找字段并在它们被注释时发挥它的魔力。序列化步骤就像一个魅力,我得到一个输出字符串,如: {"TYPE":"Type1","encryptedField":"aGAzLwT47gE/QNlUuAhnJg==","unencryptedField":"plaintext"}

但是解密很糟糕。我不能让它工作:我不确定要实现什么东西来结合多态性和解密。

如果我删除 @JsonDeserialize 注释,让 Jackson 做它的事情,它会正确反序列化多态但使用加密字段。如果我尝试使用我的自定义解串器,我会收到从 NPE 到 Jackson 的各种错误。我想在我的反序列化器中实现的是:

  1. Jackson,反序列化这个东西,因为你知道如何将类型信息与加密字段一起使用
  2. 在返回之前,让我对实例进行解密(不需要输入正确,我可以通过反射访问)。

这是我目前所拥有的:

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

但这会失败并出现错误或抱怨 EncryptedDeserializer 没有默认(无 arg)构造函数,或者我确实尝试了不同的选项但我一直卡住。

【问题讨论】:

  • github 上的 jackson-crypto 会这样做,但会产生一些不同的输出。它使用 bean 序列化修饰符来包装其他(反)序列化器。你可以找到这个here的代码。

标签: java json encryption jackson deserialization


【解决方案1】:

正如你所推断的,你需要 @JsonTypeInfo 的东西来实现多态性。

自定义解串器是实现加密逻辑的一种方法。如果您愿意,您可以随时在构造函数上尝试使用 @JsonCreator 注释进行反序列化(并在其中包含解密逻辑),并通过自定义 getter 上的 @JsonProperty 注释处理加密。

关于“EncryptedDeserializer has no default (no arg) constructor”的具体错误——为什么不直接创建一个(即使它是private)? Jackson 使用这些东西通过反射进行实例化。

【讨论】:

  • 您能否提供一个有关如何实现自定义多态反序列化器(无解密)的示例?如何做到这一点的技术性让我感到困惑,而不是解密。构造函数的问题只是我尝试过但未能实现的众多事情之一,我知道如何在其中放置一个,但它仍然无法正常工作。我不知道如何做多态自定义反序列化器,这就是阻止我的原因
  • 根据fasterxml.github.io/jackson-databind/javadoc/2.2.0/com/…@JsonDeserialize 是“通过附加到“setter”方法或字段或值类来配置反序列化方面的注释”。我不认为您可以将它直接应用于接口,但您应该能够将其应用于抽象类。我将尝试提出一个可行的示例,待命。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-25
  • 2014-08-10
相关资源
最近更新 更多