在java中敏感数据入参出参时自定义加解密注解介绍

547 阅读1分钟

应用场景

数据库中,身份证、手机号等隐私数据密文存储,Java返回数据给前端时需要解密,前端查询传入参数时,需要将数据加密,否则匹配不到数据库中存储的密文数据。

解决方案

自定义序列化解密注解,在返回给前端时,对数据解密。自定义反序列化加密注解,前端传参时,对数据加密。

加密注解

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonDeserialize(using = EncryptDeserializer.class)
public @interface Encrypt {
}

加密反序列化器

public class EncryptDeserializer extends JsonDeserializer<String> {
 
    @Override
    public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
        String value = jsonParser.getValueAsString();
        if (StringUtils.isNotBlank(value)) {
            if (ReUtil.contains(ReConstant.ID_CARD, value) || ReUtil.contains(ReConstant.MOBILE, value)) {
                return PasswordUtil.encrypt(value);
            }
        }
        return value;
    }
 
}

正则常量表达式常量类

public class ReConstant {
 
    /**
     * 身份证号码正则表达式
     */
    public static final String ID_CARD = "^(\d{15}$|^\d{18}$|^\d{17}(\d|X|x))$";
 
    /**
     * 手机号码正则表达式
     */
    public static final String MOBILE = "^1[3-9]\d{9}$";
 
    /**
     * 固定电话正则表达式
     */
    public static final String FIXED_PHONE = "^0\d{2,3}-?\d{7,8}$";
 
    /**
     * 邮箱正则表达式
     */
    public static final String EMAIL = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$";
 
}

解密注解

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@JacksonAnnotationsInside
@JsonSerialize(using = DecryptSerializer.class)
public @interface Decrypt {
}

解密序列化器

@NoArgsConstructor
@AllArgsConstructor
public class DecryptSerializer extends JsonSerializer<String> implements ContextualSerializer {
 
    private Decrypt decrypt;
 
 
    @Override
    public void serialize(String s, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        jsonGenerator.writeString(decrypt(s));
    }
 
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
        if (beanProperty != null) {
            if (Objects.equals(beanProperty.getType().getRawClass(), String.class)) {
                Decrypt decrypt = beanProperty.getAnnotation(Decrypt.class);
                if (decrypt == null) {
                    decrypt = beanProperty.getContextAnnotation(Decrypt.class);
                }
                if (decrypt != null) {
                    return new DecryptSerializer(decrypt);
                }
            }
            return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
        }
        return serializerProvider.findNullValueSerializer(null);
    }
 
    private String decrypt(String s) {
        if (StrUtil.isNotBlank(s)) {
            String value = PasswordUtil.decrypt(s);
            // 正则表达式判断是否为身份证或手机号
            if (ReUtil.contains(ReConstant.ID_CARD, value) || ReUtil.contains(ReConstant.MOBILE, value)) {
                return value;
            }
        }
        return s;
    }
}

 返回给前端的对象

    @ApiModelProperty(value = "证件号码")
    @Encrypt
    private String idcard;
 
    @ApiModelProperty(value = "联系电话")
    @Encrypt
    private String tel;

 编辑数据时,需要将身份证、手机号解密

    @ApiModelProperty(value = "证件号码")
    @Decrypt
    private String idcard;   
 
    @ApiModelProperty(value = "联系电话")
    @Decrypt
    private String tel;