自定義注解+攔截器優(yōu)雅的實(shí)現(xiàn)敏感數(shù)據(jù)的加解密!
一、什么是Mybatis Plugin
//語句執(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)??
二、實(shí)現(xiàn)基于注解的敏感信息加解密攔截器
2.1 實(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 定義需要加密解密的敏感信息注解
/**??
?*?注解敏感信息類的注解??
?*/??
@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)類
public?interface?EncryptUtil?{??
??????
????/**??
?????*?加密??
?????*??
?????*?@param?declaredFields?paramsObject所聲明的字段??
?????*?@param?paramsObject???mapper中paramsType的實(shí)例??
?????*?@return?T??
?????*?@throws?IllegalAccessException?字段不可訪問異常??
?????*/??
??????T?encrypt(Field[]?declaredFields,?T?paramsObject)?throws?IllegalAccessException;??
}??
@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截器
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)?{?}??
???
}??
@Intercepts?注解開啟攔截器,@Signature?注解定義攔截器的實(shí)際類型。type 屬性指定當(dāng)前攔截器使用StatementHandler 、ResultSetHandler、ParameterHandler,Executor的一種
method 屬性指定使用以上四種類型的具體方法(可進(jìn)入class內(nèi)部查看其方法)。
args 屬性指定預(yù)編譯語句
/**??
?*?加密攔截器??
?*?注意@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)類
public?interface?DecryptUtil?{??
???
????/**??
?????*?解密??
?????*??
?????*?@param?result?resultType的實(shí)例??
?????*?@return?T??
?????*?@throws?IllegalAccessException?字段不可訪問異常??
?????*/??
??????T?decrypt(T?result)?throws?IllegalAccessException;??
??????
}??
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í)體類中需要加解密的字段

paramType=User?resultType=User?便可實(shí)現(xiàn)脫離業(yè)務(wù)層,基于mybatis攔截器的加解密操作。推薦閱讀:
內(nèi)容包含Java基礎(chǔ)、JavaWeb、MySQL性能優(yōu)化、JVM、鎖、百萬并發(fā)、消息隊(duì)列、高性能緩存、反射、Spring全家桶原理、微服務(wù)、Zookeeper、數(shù)據(jù)結(jié)構(gòu)、限流熔斷降級(jí)......等技術(shù)棧!
?戳閱讀原文領(lǐng)?。?/span>? ? ? ? ? ? ? ??? ??? ? ? ? ? ? ? ? ? ?朕已閱?
評(píng)論
圖片
表情

