jackson自定义序列化反序列化注解加解密字段

jackson自定义序列化反序列化注解加解密字段

1 问题场景

一些场景中,数据库字段用于存储json格式数据,处于安全的考虑,该json数据中,某些敏感信息字段需要做加密存储,例如身份证号、手机号等。如果将整个json数据进行加密处理,加密后的数据较大,只对需解密的字段进行加密处理更符合实际。

如何实现呢?

之前写过一篇脱敏注解,通过自定义序列化实现的,结合来看,其实可以复用之前的脱敏注解的模式,定义字段加解密注解,通过自定义序列化和反序列化实现。

2 代码实现

  • 注解类
import com.test.jsonencrypt.EncryptJsonFiledDeSerializer;
import com.test.jsonencrypt.EncryptJsonFiledSerializer;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * <pre>
 * 加解密注解,标注在属性上
 * </pre>
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside
// 使用自定义的序列化实现
@JsonSerialize(using = EncryptJsonFiledSerializer.class)
// 使用自定义的序列化实现
@JsonDeserialize(using = EncryptJsonFiledDeSerializer.class)
public @interface EncryptJsonFiled {
    
    

}
  • 自定义序列化实现类
import com.test.jsonencrypt.annotation.EncryptJsonFiled;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import com.test.util.EncryUtil;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.util.Objects;

/**
 * <pre>
 * 序列化注解自定义实现
 * JsonDeserializer<String>:指定String类型,deserialize()方法用于将修改后的数据载入
 * Jackson使用ContextualSerializer在序列化时获取字段注解的属性
 * </pre>
 */
public class EncryptJsonFiledDeSerializer extends JsonDeserializer<String> implements ContextualDeserializer {
    
    

    @Override
    public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
    
    
        String valueAsString = p.getValueAsString();
        // 数据不为空时解密数据
        if (StringUtils.isNotBlank(valueAsString)) {
    
    
            // EncryUtil为封装的加解密工具
            return EncryUtil.decrypt(valueAsString);
        }
        return valueAsString;
    }

    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException {
    
    
        EncryptJsonFiled annotation = property.getAnnotation(EncryptJsonFiled.class);
        // 只针对String类型
        if (Objects.nonNull(annotation)&&Objects.equals(String.class, property.getType().getRawClass())) {
    
    
            return this;
        }
        return ctxt.findContextualValueDeserializer(property.getType(), property);
    }
}
  • 自定义反序列化实现类
import com.test.jsonencrypt.annotation.EncryptJsonFiled;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.test.util.EncryUtil;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.util.Objects;

/**
 * <pre>
 * 序列化注解自定义实现
 * JsonSerializer<String>:指定String类型,serialize()方法用于将修改后的数据载入
 * Jackson使用ContextualSerializer在序列化时获取字段注解的属性
 * </pre>
 */
public class EncryptJsonFiledSerializer extends JsonSerializer<String> implements ContextualSerializer {
    
    

    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
    
    
        // 数据不为空时加密数据
        if (StringUtils.isNotBlank(value)) {
    
    
            String encrypt = EncryUtil.encry(value);
            gen.writeString(encrypt);
            return;
        }
        gen.writeString(value);
    }

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
    
    
        EncryptJsonFiled annotation = property.getAnnotation(EncryptJsonFiled.class);
        // 只针对String类型
        if (Objects.nonNull(annotation)&&Objects.equals(String.class, property.getType().getRawClass())) {
    
    
            return this;
        }
        return prov.findValueSerializer(property.getType(), property);
    }

}

3 测试

  • 用于测试的简易实体类
@Data
@Accessors(chain = true)
public class User {
    
    

    private String name;
    
    private int age;
    
    @EncryptJsonFiled
    private String idCard;

}
  • 测试类
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * <pre>
 * 测试加解密注解
 * </pre>
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestEntry {
    
    

    @Test
    public void test() throws JsonProcessingException {
    
    
        User user = new User().setAge(11)
                .setName("小明")
                .setIdCard("13523451124");
        // 注意使用Jackson的json工具
        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writeValueAsString(user);
        System.out.println("序列化后的json数据:" + json);

        User user1 = objectMapper.readValue(json, User.class);
        System.out.println("反序列化后的解密数据:" + user1.getIdCard());
    }

}

测试结果:

序列化后的json数据:{
    
    "name":"小明","age":11,"idCard":"2f3d8f692eeaac2cbc60423ed99aed63"}
反序列化后的解密数据:13523451124

猜你喜欢

转载自blog.csdn.net/weixin_46505978/article/details/128577970