【发布时间】: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 的各种错误。我想在我的反序列化器中实现的是:
- Jackson,反序列化这个东西,因为你知道如何将类型信息与加密字段一起使用
- 在返回之前,让我对实例进行解密(不需要输入正确,我可以通过反射访问)。
这是我目前所拥有的:
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