一、前言
客户要求系统的敏感字段需要使用国密SM4算法进行加密,需要在数据库中看到加密的数据。因为平台的持久层使用的是Hibernate,因此利用hibernate的拦截器在数据读取时进行解密,在数据进行持久化时进行加密实现。
二、实现思路
1、敏感实体类上添加加密注解,可以通过注解区分出哪些实体类需要加密
2、敏感实体类的字段也需要增加加密注解,用于区分哪些字段需要加密
3、利用在Hibernate的拦截器EmptyInterceptor的对应事件,通过反射获取需要处理的实体类和字段,在数据入库前在拦截器对应的方法对数据进行加密处理,在数据读取时在拦截器中对数据进行解密处理。
4、以上处理当存储之后加密字段已修改成加密,需要重新解密,则利用Hibernate的监听器PostInsertEventListener的对应事件,通过反射获取需要处理的实体类和字段,在存储成功后在进行解密(若保存后无需使用该对象时可不写监听器)。
三、Hibernate拦截器简介
Hibernate定义了一个拦截器,位于org.hibernate.Interceptor,提供了一系列的拦截器方法。详细可见Hibernate官网文档
public class EmptyInterceptor implements Interceptor, Serializable {
public static final Interceptor INSTANCE = new EmptyInterceptor();
protected EmptyInterceptor() {
}
public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
}
public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) {
return false;
}
public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
return false;
}
public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
return false;
}
public void postFlush(Iterator entities) {
}
public void preFlush(Iterator entities) {
}
public Boolean isTransient(Object entity) {
return null;
}
public Object instantiate(String entityName, EntityMode entityMode, Serializable id) {
return null;
}
public int[] findDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) {
return null;
}
...
}
这里只需要用到三个方法,分别是onLoad初始化前调用、onSave保存前调用和onFlushDirty更新对象前调用。需要注意的是onSave的方法并不是指保存时调用,而是指Hibernate执行insert操作时才会调用,而update操作对应的拦截方法是onFlushDirty
方法名 |
描述 |
onLoad |
在初始化对象之前调用。拦截器可能会更改状态,该状态将被传播到持久对象。请注意,当调用此方法时,实体将是该类的一个未初始化的空实例。 |
onSave |