使用Jackson加密/解密JSON字段

Jackson是Java平台很是流行的JSON解析框架,并且扩展性很强,本文经过添加一个Module来增强JSON字段的解析来实现单个字段的加密与解密功能。java

基本想法是使用Jackson来处理自定义的注解,在须要加密/解密的字段上添加上相应的注解,先定义个自定义的注解:git

@JacksonAnnotation
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
public @interface Encrypt {}
复制代码

而后在须要在POJO中对字段添加@Encrypt注解:github

public  final class User {

    @Encrypt
    private String name;
    private String guid;

    @Encrypt
    private User first;

    @Encrypt
    private int age;
    
    //... getters/setters
}
复制代码

完成上面的工做后,而后再来扩展Jackson来处理@Encrypt注解进行字段加密,先定义个Jackson的Module:json

public class EncryptionModule extends Module {

    public final static String ARTIFACT_ID = "jackson-hb-encryption";
    public final static Version VERSION = new Version(1, 0, 0, null);

    private EncryptionModule(){

    }

    ...

    @Override
    public void setupModule(SetupContext setupContext) {
        setupContext.addBeanSerializerModifier(new EncryptedSerializerModifier());
        setupContext.addBeanDeserializerModifier(new EncryptedDeserializerModifier());
    }


    /** * 建立一个{@link ObjectMapper}对象,支持{@link Encrypt}注解。 * @return */
    public static ObjectMapper createMapper(){
        ObjectMapper objectMapper  = new ObjectMapper();
        objectMapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
        objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.configure( SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);
        objectMapper.registerModule(new EncryptionModule());
        return objectMapper;
    }
}
复制代码

建立module只须要继承org.codehaus.jackson.map.Module类,EncryptionModulesetupModule方法中添加了一个序列化修改器和反序列化修改器,EncryptedSerializerModifier重载changeProperties方法,遍历属性若是属性有@Encrypt注解那么须要将属性的JsonSerializer设置为EncryptedJsonSerializerapp

public class EncryptedSerializerModifier extends BeanSerializerModifier {


    @Override
    public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BasicBeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {

        /* 遍历beanProperties处理Encrypt.class注解 */
        List<BeanPropertyWriter> newWriter = new ArrayList<>();
        for(BeanPropertyWriter writer : beanProperties){
            if(null == writer.getAnnotation(Encrypt.class)){
                newWriter.add(writer);
            }else{
                JsonSerializer<Object> serializer = new EncryptedJsonSerializer(writer.getSerializer());
                newWriter.add(writer.withSerializer(serializer));
            }
        }

        return newWriter;
    }
}

复制代码

EncryptedJsonSerializer是自定义的序列化工具,它实现属性字段的加密功能:框架

public class EncryptedJsonSerializer extends JsonSerializer<Object> {

    /** * 默认序列化工具对象 */
    private final JsonSerializer<Object> serializer;

    public EncryptedJsonSerializer(JsonSerializer<Object> serializer) {
        this.serializer = serializer;
    }

    @Override
    public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
        StringWriter stringWriter = new StringWriter();
        ObjectCodec objectCodec = jsonGenerator.getCodec();
        JsonGenerator nestedGenerator = null;

        //空对象或空字符串不处理。
        if(o == null || Strings.isNullOrEmpty(String.valueOf(o))){
            if (serializer == null) {
                serializerProvider.defaultSerializeValue(o, jsonGenerator);
            }else{
                serializer.serialize(o, jsonGenerator, serializerProvider);
            }

            return;
        }

        /* 生成一个新的JsonGenerator,用于将o写入。 */
        if(objectCodec instanceof ObjectMapper){
            nestedGenerator = ((ObjectMapper) objectCodec).getJsonFactory().createJsonGenerator(stringWriter);
        }

        if (nestedGenerator == null) {
            throw new NullPointerException("nestedGenerator == null");
        }

        /* 将数据写入到新生成的JsonGenerator中 */
        if (serializer == null) {
            serializerProvider.defaultSerializeValue(o, nestedGenerator);
        }else{
            serializer.serialize(o, nestedGenerator, serializerProvider);
        }

        nestedGenerator.close();
        /* JsonGenerator会生成一个带双引号的字符串, 将数据加密后写入。 */
        String value = stringWriter.getBuffer().toString();
        try {
            //空字符串不加密
            jsonGenerator.writeString(AESTools.encrypt(value));
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }
}

复制代码

EncryptedJsonSerializer的处理是先判断是否为空对象或空字符串,若是是那就将它们直接收入到jsonGenerator,不然的话建立一个新的nestedGenerator并将数据写入进去,而后再拿出来进行AES加密,最后写入到原始的jsonGenerator中,这样就完成了属性的加密以久序列化工做。ide

参考资源

相关文章
相关标签/搜索