mongodb敏感数据加解密
Posted kuailefangyuan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mongodb敏感数据加解密相关的知识,希望对你有一定的参考价值。
mongodb敏感数据加解密
一、问题背景
公司项目涉及敏感数据存MongoDB库,基于风险要求,敏感数据做SM4国密加密后密文存库,读取时SM4解密为明文。
二、解决方案
项目采用SpringBoot+MongoDB技术框架,使用Spring Data MongoDB的持久化方案。
解决思路:
1、在数据写到mongodb之前,做一层拦截,对明文做SM4加密处理。
2、在mongodb读取数据之后,做一层拦截,对密文做SM4解密处理。
这里介绍下AbstractMongoEventListener类,该类监听Mongodb的增删改查操作,并提供增删改查操作前后的事件,如下图所示:
其中:
onBeforeConvert
:在 object 被MongoConverter
转换为Document
之前,在MongoTemplate
insert
,insertList
和save
操作中调用。onBeforeSave
:在将Document
插入或保存在数据库中之前,请在MongoTemplate
insert
,insertList
和save
操作中调用。onAfterSave
:在**将Document
插入或保存在数据库中之后,**在MongoTemplate
insert
,insertList
和save
操作中调用。onAfterLoad
:从数据库中检索Document
后,在MongoTemplate
find
,findAndRemove
,findOne
和getCollection
方法中调用。onAfterConvert
:从数据库中检索到Document
后,在MongoTemplate
find
,findAndRemove
,findOne
和getCollection
方法中调用被转换为 POJO。- onAfterDelete : 在数据库删除Document之后调用。
- onBeforeDelete: 在数据库删除Document之前调用。
这里我们只需继承该上述基类,并覆写其中onBeforeConvert和onAfterConvert方法,即可实现在对象写到mongodb之前做SM4加密,在mongodb读取document转换到对象之后做SM4解密。
三、具体实现
1、首先实现一个SM4Enc字段注解。
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SM4Enc
SM4EncType encType() default SM4EncType.NAME;
其中加密类型不同,对应的SM4加解密索引也不同,这里定义一个SM4加密索引枚举值:
public enum SM4EncType
NAME("A001"),
PHONE("B001"),
NONE("NONE");
private String keyIdx;
SM4EncType(String keyIdx)
this.keyIdx = keyIdx;
public String keyIdx()
return keyIdx;
2、实现自定义的mongodb读写时间监听器MongoReadWriteEventListener,监听onBeforeConvert
和onAfterConvert
事件,并对标有@SM4Enc注解的字段进行写前SM4加密,读后SM4解密处理。
@Component
@Slf4j
public class MongoReadWriteEventListener extends AbstractMongoEventListener<Object>
@Override
public void onAfterConvert(AfterConvertEvent<Object> event)
if (event.getSource() != null)
ReflectionUtils.doWithFields(event.getSource().getClass(), field ->
// @SM4Enc注解字段,读库后做SM4解密
if (field.isAnnotationPresent(SM4Enc.class))
ReflectionUtils.makeAccessible(field);
Object value = field.get(event.getSource());
if (value != null)
String ciphertext = (String) value;
if (StringUtils.isNotBlank(ciphertext))
String plainText = SM4ConverterUtil.convertToEntityAttribute(ciphertext);
log.info("解密前:,解密后:", ciphertext, plainText);
field.set(event.getSource(), plainText);
);
@Override
public void onBeforeConvert(BeforeConvertEvent<Object> event)
if (event.getSource() != null)
ReflectionUtils.doWithFields(event.getSource().getClass(), field ->
// @SM4Enc注解字段,写库前做SM4加密
if (field.isAnnotationPresent(SM4Enc.class))
ReflectionUtils.makeAccessible(field);
// 获取加密类型
SM4Enc sm4Enc = field.getAnnotation(SM4Enc.class);
SM4EncType encType = sm4Enc.encType();
Object value = field.get(event.getSource());
if (value != null)
String plainText = (String) value;
String cipherText = SM4ConverterUtil.convertToDatabaseColumn(encType.keyIdx(), plainText);
log.info("加密前:,加密后:", plainText, cipherText);
field.set(event.getSource(), cipherText);
);
以上是关于mongodb敏感数据加解密的主要内容,如果未能解决你的问题,请参考以下文章