天天看點

如何使用MyBatis進行資料存儲的加密、解密

作者:頑強小貓BX
背景:在大部分的系統中,出于使用者的隐私安全考慮,都會對資料庫内容進行加密,那麼在編寫業務代碼邏輯時加密也不太現實。于是通用的加解密插件就應運而生,本文将采用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();
}
           
如何使用MyBatis進行資料存儲的加密、解密
  • 解密
  • @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;
}
           
如何使用MyBatis進行資料存儲的加密、解密
如何使用MyBatis進行資料存儲的加密、解密

結果:

存儲:

如何使用MyBatis進行資料存儲的加密、解密

查詢:

如何使用MyBatis進行資料存儲的加密、解密
我是Tz ,想把我遇到的問題都分享給你,想看更多精彩内容,請關注我的微信公衆号zhuangtian~~

繼續閱讀