<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          自定義注解+攔截器優(yōu)雅的實(shí)現(xiàn)敏感數(shù)據(jù)的加解密!

          共 9360字,需瀏覽 19分鐘

           ·

          2022-03-03 01:34

          程序員的成長之路
          互聯(lián)網(wǎng)/程序員/技術(shù)/資料共享?
          關(guān)注

          閱讀本文大概需要 5.5 分鐘。
          來自:blog.csdn.net/bbcckkl/article/details/104069487
          在實(shí)際生產(chǎn)項(xiàng)目中,經(jīng)常需要對(duì)如身份證信息、手機(jī)號(hào)、真實(shí)姓名等的敏感數(shù)據(jù)進(jìn)行加密數(shù)據(jù)庫存儲(chǔ),但在業(yè)務(wù)代碼中對(duì)敏感信息進(jìn)行手動(dòng)加解密則十分不優(yōu)雅,甚至?xí)嬖阱e(cuò)加密、漏加密、業(yè)務(wù)人員需要知道實(shí)際的加密規(guī)則等的情況。
          本文將介紹使用springboot+mybatis攔截器+自定義注解的形式對(duì)敏感數(shù)據(jù)進(jìn)行存儲(chǔ)前攔截加密的詳細(xì)過程。

          一、什么是Mybatis Plugin

          在mybatis官方文檔中,對(duì)于Mybatis plugin的的介紹是這樣的:
          MyBatis 允許你在已映射語句執(zhí)行過程中的某一點(diǎn)進(jìn)行攔截調(diào)用。默認(rèn)情況下,MyBatis 允許使用插件來攔截的方法調(diào)用包括:
          //語句執(zhí)行攔截??
          Executor?(update,?query,?flushStatements,?commit,?rollback,?getTransaction,?close,?isClosed)??
          ??
          //?參數(shù)獲取、設(shè)置時(shí)進(jìn)行攔截??
          ParameterHandler?(getParameterObject,?setParameters)??
          ??
          //?對(duì)返回結(jié)果進(jìn)行攔截??
          ResultSetHandler?(handleResultSets,?handleOutputParameters)??
          ??
          //sql語句攔截??
          StatementHandler?(prepare,?parameterize,?batch,?update,?query)??
          簡而言之,即在執(zhí)行sql的整個(gè)周期中,我們可以任意切入到某一點(diǎn)對(duì)sql的參數(shù)、sql執(zhí)行結(jié)果集、sql語句本身等進(jìn)行切面處理?;谶@個(gè)特性,我們便可以使用其對(duì)我們需要進(jìn)行加密的數(shù)據(jù)進(jìn)行切面統(tǒng)一加密處理了(分頁插件 pageHelper 就是這樣實(shí)現(xiàn)數(shù)據(jù)庫分頁查詢的)。

          二、實(shí)現(xiàn)基于注解的敏感信息加解密攔截器

          2.1 實(shí)現(xiàn)思路

          對(duì)于數(shù)據(jù)的加密與解密,應(yīng)當(dāng)存在兩個(gè)攔截器對(duì)數(shù)據(jù)進(jìn)行攔截操作
          參照官方文檔,因此此處我們應(yīng)當(dāng)使用ParameterHandler攔截器對(duì)入?yún)⑦M(jìn)行加密
          使用ResultSetHandler攔截器對(duì)出參進(jìn)行解密操作。
          圖片
          目標(biāo)需要加密、解密的字段可能需要靈活變更,此時(shí)我們定義一個(gè)注解,對(duì)需要加密的字段進(jìn)行注解,那么便可以配合攔截器對(duì)需要的數(shù)據(jù)進(jìn)行加密與解密操作了。
          mybatis的interceptor接口有以下方法需要實(shí)現(xiàn)。
          public?interface?Interceptor?{??
          ???
          ??//主要參數(shù)攔截方法??
          ??Object?intercept(Invocation?invocation)?throws?Throwable;??
          ???
          ??//mybatis插件鏈??
          ??default?Object?plugin(Object?target)?{return?Plugin.wrap(target,?this);}??
          ???
          ??//自定義插件配置文件方法??
          ??default?void?setProperties(Properties?properties)?{}??
          ???
          }??

          2.2 定義需要加密解密的敏感信息注解

          定義注解敏感信息類(如實(shí)體類POJO\PO)的注解
          /**??
          ?*?注解敏感信息類的注解??
          ?*/
          ??
          @Inherited??
          @Target({?ElementType.TYPE?})??
          @Retention(RetentionPolicy.RUNTIME)??
          public?@interface?SensitiveData?{??
          }??
          定義注解敏感信息類中敏感字段的注解
          /**??
          ?*?注解敏感信息類中敏感字段的注解??
          ?*/
          ??
          @Inherited??
          @Target({?ElementType.Field?})??
          @Retention(RetentionPolicy.RUNTIME)??
          public?@interface?SensitiveField?{??
          }??

          2.3 定義加密接口及其實(shí)現(xiàn)類

          定義加密接口,方便以后拓展加密方法(如AES加密算法拓展支持PBE算法,只需要注入時(shí)指定一下便可)
          public?interface?EncryptUtil?{??
          ??????
          ????/**??
          ?????*?加密??
          ?????*??
          ?????*?@param?declaredFields?paramsObject所聲明的字段??
          ?????*?@param?paramsObject???mapper中paramsType的實(shí)例??
          ?????*?@return?T??
          ?????*?@throws?IllegalAccessException?字段不可訪問異常??
          ?????*/
          ??
          ??????T?encrypt(Field[]?declaredFields,?T?paramsObject)?throws?IllegalAccessException;??
          }??
          EncryptUtil 的AES加密實(shí)現(xiàn)類,此處AESUtil為自封裝的AES加密工具,需要的小伙伴可以自行封裝,本文不提供。
          @Component??
          public?class?AESEncrypt?implements?EncryptUtil?{??
          ??????
          ????@Autowired??
          ????AESUtil?aesUtil;??
          ???
          ????/**??
          ?????*?加密??
          ?????*??
          ?????*?@param?declaredFields?paramsObject所聲明的字段??
          ?????*?@param?paramsObject???mapper中paramsType的實(shí)例??
          ?????*?@return?T??
          ?????*?@throws?IllegalAccessException?字段不可訪問異常??
          ?????*/
          ??
          ????@Override??
          ????public??T?encrypt(Field[]?declaredFields,?T?paramsObject)?throws?IllegalAccessException?{??
          ????????for?(Field?field?:?declaredFields)?{??
          ????????????//取出所有被EncryptDecryptField注解的字段??
          ????????????SensitiveField?sensitiveField?=?field.getAnnotation(SensitiveField.class);??
          ????????????if?(!Objects.isNull(sensitiveField))?{??
          ????????????????field.setAccessible(true);??
          ????????????????Object?object?=?field.get(paramsObject);??
          ????????????????//暫時(shí)只實(shí)現(xiàn)String類型的加密??
          ????????????????if?(object?instanceof?String)?{??
          ????????????????????String?value?=?(String)?object;??
          ????????????????????//加密??這里我使用自定義的AES加密工具??
          ????????????????????field.set(paramsObject,?aesUtil.encrypt(value));??
          ????????????????}??
          ????????????}??
          ????????}??
          ????????return?paramsObject;??
          ????}??
          }??

          2.4 實(shí)現(xiàn)入?yún)⒓用軘r截器

          Myabtis包中的org.apache.ibatis.plugin.Interceptor攔截器接口要求我們實(shí)現(xiàn)以下三個(gè)方法
          public?interface?Interceptor?{??
          ???
          ??//核心攔截邏輯??
          ??Object?intercept(Invocation?invocation)?throws?Throwable;??
          ????
          ??//攔截器鏈??
          ??default?Object?plugin(Object?target)?{return?Plugin.wrap(target,?this);}??
          ???
          ??//自定義配置文件操作??
          ??default?void?setProperties(Properties?properties)?{?}??
          ???
          }??
          因此,參考官方文檔的示例,我們自定義一個(gè)入?yún)⒓用軘r截器。
          @Intercepts?注解開啟攔截器,@Signature?注解定義攔截器的實(shí)際類型。
          @Signature中
          • type 屬性指定當(dāng)前攔截器使用StatementHandler 、ResultSetHandler、ParameterHandler,Executor的一種

          • method 屬性指定使用以上四種類型的具體方法(可進(jìn)入class內(nèi)部查看其方法)。

          • args 屬性指定預(yù)編譯語句

          此處我們使用了?ParameterHandler.setParamters()方法,攔截mapper.xml中paramsType的實(shí)例(即在每個(gè)含有paramsType屬性mapper語句中,都執(zhí)行該攔截器,對(duì)paramsType的實(shí)例進(jìn)行攔截處理)
          /**??
          ?*?加密攔截器??
          ?*?注意@Component注解一定要加上??
          ?*??
          ?*?@author?:?tanzj??
          ?*?@date?:?2020/1/19.??
          ?*/
          ??
          @Slf4j??
          @Component??
          @Intercepts({??
          ????????@Signature(type?=?ParameterHandler.class,?method?=?"setParameters",?args?=?PreparedStatement.class),??
          })??
          public?class?EncryptInterceptor?implements?Interceptor?
          {??
          ???
          ????private?final?EncryptDecryptUtil?encryptUtil;??
          ???
          ????@Autowired??
          ????public?EncryptInterceptor(EncryptDecryptUtil?encryptUtil)?{??
          ????????this.encryptUtil?=?encryptUtil;??
          ????}??
          ???
          ????@Override??
          ?????
          ????@Override??
          ????public?Object?intercept(Invocation?invocation)?throws?Throwable?{??
          ????????//@Signature?指定了?type=?parameterHandler?后,這里的?invocation.getTarget()?便是parameterHandler???
          ????????//若指定ResultSetHandler?,這里則能強(qiáng)轉(zhuǎn)為ResultSetHandler??
          ????????ParameterHandler?parameterHandler?=?(ParameterHandler)?invocation.getTarget();??
          ????????//?獲取參數(shù)對(duì)像,即?mapper?中?paramsType?的實(shí)例??
          ????????Field?parameterField?=?parameterHandler.getClass().getDeclaredField("parameterObject");??
          ????????parameterField.setAccessible(true);??
          ????????//取出實(shí)例??
          ????????Object?parameterObject?=?parameterField.get(parameterHandler);??
          ????????if?(parameterObject?!=?null)?{??
          ????????????Class?parameterObjectClass?=?parameterObject.getClass();??
          ????????????//校驗(yàn)該實(shí)例的類是否被@SensitiveData所注解??
          ????????????SensitiveData?sensitiveData?=?AnnotationUtils.findAnnotation(parameterObjectClass,?SensitiveData.class);??
          ????????????if?(Objects.nonNull(sensitiveData))?{??
          ????????????????//取出當(dāng)前當(dāng)前類所有字段,傳入加密方法??
          ????????????????Field[]?declaredFields?=?parameterObjectClass.getDeclaredFields();??
          ????????????????encryptUtil.encrypt(declaredFields,?parameterObject);??
          ????????????}??
          ????????}??
          ????????return?invocation.proceed();??
          ????}??
          ???
          ????/**??
          ?????*?切記配置,否則當(dāng)前攔截器不會(huì)加入攔截器鏈??
          ?????*/
          ??
          ????@Override??
          ????public?Object?plugin(Object?o)?{??
          ????????return?Plugin.wrap(o,?this);??
          ????}??
          ???
          ????//自定義配置寫入,沒有自定義配置的可以直接置空此方法??
          ????@Override??
          ????public?void?setProperties(Properties?properties)?{??
          ????}??
          }??
          至此完成自定義加密攔截加密。

          2.5 定義解密接口及其實(shí)現(xiàn)類

          解密接口,其中result為mapper.xml中resultType的實(shí)例。
          public?interface?DecryptUtil?{??
          ???
          ????/**??
          ?????*?解密??
          ?????*??
          ?????*?@param?result?resultType的實(shí)例??
          ?????*?@return?T??
          ?????*?@throws?IllegalAccessException?字段不可訪問異常??
          ?????*/
          ??
          ??????T?decrypt(T?result)?throws?IllegalAccessException;??
          ??????
          }??
          解密接口AES工具解密實(shí)現(xiàn)類
          public?class?AESDecrypt?implements?DecryptUtil?{??
          ??????
          ????@Autowired??
          ????AESUtil?aesUtil;??
          ??????
          ????/**??
          ?????*?解密??
          ?????*??
          ?????*?@param?result?resultType的實(shí)例??
          ?????*?@return?T??
          ?????*?@throws?IllegalAccessException?字段不可訪問異常??
          ?????*/
          ??
          ????@Override??
          ????public??T?decrypt(T?result)?throws?IllegalAccessException?{??
          ????????//取出resultType的類??
          ????????Class?resultClass?=?result.getClass();??
          ????????Field[]?declaredFields?=?resultClass.getDeclaredFields();??
          ????????for?(Field?field?:?declaredFields)?{??
          ????????????//取出所有被EncryptDecryptField注解的字段??
          ????????????SensitiveField?sensitiveField?=?field.getAnnotation(SensitiveField.class);??
          ????????????if?(!Objects.isNull(sensitiveField))?{??
          ????????????????field.setAccessible(true);??
          ????????????????Object?object?=?field.get(result);??
          ????????????????//只支持String的解密??
          ????????????????if?(object?instanceof?String)?{??
          ????????????????????String?value?=?(String)?object;??
          ????????????????????//對(duì)注解的字段進(jìn)行逐一解密??
          ????????????????????field.set(result,?aesUtil.decrypt(value));??
          ????????????????}??
          ????????????}??
          ????????}??
          ????????return?result;??
          ????}??
          }??

          2.6 定義出參解密攔截器

          @Slf4j??
          @Component??
          @Intercepts({??
          ????????@Signature(type?=?ResultSetHandler.class,?method?=?"handleResultSets",?args?=?{Statement.class})??
          })??
          public?class?DecryptInterceptor?implements?Interceptor?
          {??
          ???
          ????@Autowired??
          ????DecryptUtil?aesDecrypt;??
          ???
          ????@Override??
          ????public?Object?intercept(Invocation?invocation)?throws?Throwable?{??
          ????????//取出查詢的結(jié)果??
          ????????Object?resultObject?=?invocation.proceed();??
          ????????if?(Objects.isNull(resultObject))?{??
          ????????????return?null;??
          ????????}??
          ????????//基于selectList??
          ????????if?(resultObject?instanceof?ArrayList)?{??
          ????????????ArrayList?resultList?=?(ArrayList)?resultObject;??
          ????????????if?(!CollectionUtils.isEmpty(resultList)?&&?needToDecrypt(resultList.get(0)))?{??
          ????????????????for?(Object?result?:?resultList)?{??
          ????????????????????//逐一解密??
          ????????????????????aesDecrypt.decrypt(result);??
          ????????????????}??
          ????????????}??
          ????????//基于selectOne??
          ????????}?else?{??
          ????????????if?(needToDecrypt(resultObject))?{??
          ????????????????aesDecrypt.decrypt(resultObject);??
          ????????????}??
          ????????}??
          ????????return?resultObject;??
          ????}??
          ???
          ????private?boolean?needToDecrypt(Object?object)?{??
          ????????Class?objectClass?=?object.getClass();??
          ????????SensitiveData?sensitiveData?=?AnnotationUtils.findAnnotation(objectClass,?SensitiveData.class);??
          ????????return?Objects.nonNull(sensitiveData);??
          ????}??
          ???
          ???
          ????@Override??
          ????public?Object?plugin(Object?target)?{??
          ????????return?Plugin.wrap(target,?this);??
          ????}??
          ???
          ????@Override??
          ????public?void?setProperties(Properties?properties)?{??
          ???
          ????}??
          }??
          至此完成解密攔截器的配置工作。

          3、注解實(shí)體類中需要加解密的字段

          圖片
          此時(shí)在mapper中,指定paramType=User?resultType=User?便可實(shí)現(xiàn)脫離業(yè)務(wù)層,基于mybatis攔截器的加解密操作。

          推薦閱讀:

          新來的同事問我 where 1=1 是什么意思

          寫 Java 代碼的14個(gè)好習(xí)慣

          互聯(lián)網(wǎng)初中高級(jí)大廠面試題(9個(gè)G)

          內(nèi)容包含Java基礎(chǔ)、JavaWeb、MySQL性能優(yōu)化、JVM、鎖、百萬并發(fā)、消息隊(duì)列、高性能緩存、反射、Spring全家桶原理、微服務(wù)、Zookeeper、數(shù)據(jù)結(jié)構(gòu)、限流熔斷降級(jí)......等技術(shù)棧!

          ?戳閱讀原文領(lǐng)?。?/span>? ? ? ? ? ? ? ??? ??? ? ? ? ? ? ? ? ? ?朕已閱?

          瀏覽 110
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  99国产婷婷踪合在线免费视频 | 色婷婷五月天影院 | 免费看亚洲色情视频 | 日韩电车痴汉伦理片黄色视频播放 | 免费观看靠逼网站 |