背景:在大部分的系統中,出于使用者的隐私安全考慮,都會對資料庫内容進行加密,那麼在編寫業務代碼邏輯時加密也不太現實。于是通用的加解密插件就應運而生,本文将采用mybatis的攔截器作為基礎進行實作。
思路:我們可以通過mybatis的攔截器進行參數的加密和解密
Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
// 攔截執行方法ParameterHandler (getParameterObject, setParameters)
// 攔截參數處理器ResultSetHandler (handleResultSets, handleOutputParameters)
// 攔截結果集處理器StatementHandler (prepare, parameterize, batch, update, query)
// 攔截sql建構處理器
兩個注解,一個用于實體類(SensitiveData),一個用于實體類的字段(SensitiveField)重寫mysql的攔截器Interceptor,對資料進行加密和解密
- 加密:(攔截參數處理器)
@Intercepts({@Signature(type = ParameterHandler.class, method = "setParameters", args = PreparedStatement.class)})
public Object intercept(Invocation invocation) throws Throwable {
//@Signature 指定了 type= parameterHandler 後,這裡的 invocation.getTarget() 便是parameterHandler
//若指定ResultSetHandler ,這裡則能強轉為ResultSetHandler
ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget();
log.info("============parameterHandler ==={}", parameterHandler);
// 擷取參數對像,即 mapper 中 paramsType 的執行個體
Field parameterField = parameterHandler.getClass().getDeclaredField("parameterObject");
log.info("============parameterField ==={}", parameterField);
parameterField.setAccessible(true);
// 取出執行個體
Object parameterObject = parameterField.get(parameterHandler);
log.info("============parameterObject ==={}", parameterObject);
if (!Objects.isNull(parameterObject)) {
Class<?> parameterObjectClass = parameterObject.getClass();
log.info("============parameterObjectClass ==={}", parameterObjectClass);
//校驗該執行個體的類是否被@SensitiveData所注解
SensitiveData sensitiveData = AnnotationUtil.getAnnotation(parameterObjectClass, SensitiveData.class);
log.info("============sensitiveData ==={}", sensitiveData);
if (Objects.nonNull(sensitiveData)) {
Field[] declaredFields = parameterObjectClass.getDeclaredFields();
aesEncrypt.encrypt(declaredFields, parameterObject);
}
}
log.info("==========proceed==-{}---", invocation.proceed());
return invocation.proceed();
}
- 解密
- @Intercepts({@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = Statement.class)})
public Object intercept(Invocation invocation) throws Throwable {
// 擷取結果
Object resultObj = invocation.proceed();
log.info("=====resultObj==={}", resultObj);
if (Objects.isNull(resultObj)) {
return null;
}
// 判斷是否是list
if (resultObj instanceof List) {
for (Object resultList : (List) resultObj) {
aesUtil.decrypt(resultList);
}
} else {
Class<?> aClass = resultObj.getClass();
SensitiveData annotation = AnnotationUtil.getAnnotation(aClass, SensitiveData.class);
if (Objects.nonNull(annotation)) {
aesUtil.decrypt(resultObj);
}
}
return resultObj;
}
結果:
存儲:
查詢:
我是Tz ,想把我遇到的問題都分享給你,想看更多精彩内容,請關注我的微信公衆号zhuangtian~~