monkey-api-encrypt又增強(qiáng)了一個(gè)實(shí)用功能
框架主頁(yè):https://github.com/yinjihuan/monkey-api-encrypt
背景
有陣子沒(méi)更新 monkey-api-encrypt 這個(gè)框架了,然后看了下 Github 上一些用戶(hù)提的問(wèn)題,挑了一個(gè)比較實(shí)用的進(jìn)行了修復(fù)。
說(shuō)問(wèn)題之前先簡(jiǎn)單的講下 monkey-api-encrypt 的原理,目前 monkey-api-encrypt 中核心部分就是用了 javax.servlet.Filter 來(lái)對(duì)數(shù)據(jù)進(jìn)行加解密的處理,實(shí)現(xiàn)也比較簡(jiǎn)單。
唯一要注意的就是在 Filter 中如何知道當(dāng)前訪問(wèn)的 uri 是否需要加解密,而是否需要加解密可以通過(guò)配置的方式指定,也可以通過(guò)注解的方式配置在方法上。基于注解的方式,在項(xiàng)目啟動(dòng)的時(shí)候會(huì)去掃描方法,將 uri 存儲(chǔ)起來(lái),這樣在 Filter 中就可以判斷當(dāng)前訪問(wèn)的 uri 是否需要加解密了。

uri 匹配的方式存在的問(wèn)題是對(duì)于目前比較流行的 Restful 風(fēng)格的 API 不支持,因?yàn)?uri 不是固定的,無(wú)法匹配到,這就是當(dāng)前版本要解決的問(wèn)題。
其實(shí)最開(kāi)始的版本用的是 spring 的@ResponseBodyAdvice @RequestBodyAdvice 實(shí)現(xiàn)的,后面才改成了 Filter 的方式。如果是之前的實(shí)現(xiàn),那么就不會(huì)存在今天的問(wèn)題了,因?yàn)樵?Advice 中可以獲取到當(dāng)前訪問(wèn)的 Method 對(duì)象。
下面看怎么解決如何在 Filter 中通過(guò)當(dāng)前訪問(wèn)的 uri 判斷是否需要加解密的操作。
AntPathMatcher
spring-core 包中提供了一個(gè) AntPathMatcher 類(lèi),可以用于路徑的匹配。比如我的接口格式是/users/{id},當(dāng)訪問(wèn)路徑是/users/1001 的時(shí)候,這個(gè)路徑應(yīng)該匹配到/users/{id}才對(duì),如果匹配上了/users/{id},那么就可以通過(guò)/users/{id}知道當(dāng)前接口是不是需要加解密操作。
代碼如下:
for (String u : list) {
boolean match = antPathMatcher.match(u, prefixUri);
if (match) {
return true;
}
}
list 格式:["get:/users/{id}"]
prefixUri:get:/users/1
循環(huán)將需要加解密的 uri 模板跟當(dāng)前請(qǐng)求的 uri 進(jìn)行匹配,如果匹配成功了,就證明需要加解密操作。
HandlerMapping
在做之前,我也想了下這個(gè)問(wèn)題,可以借鑒 dispatcherServlet 中的代碼。當(dāng)我們的請(qǐng)求需要轉(zhuǎn)發(fā)到對(duì)應(yīng)的方法上,dispatcherServlet 就承擔(dān)了這個(gè)工作。
通過(guò)獲取 HandlerMapping,然后獲取具體的 handler 對(duì)象,內(nèi)部邏輯我們完全不需要關(guān)心,也不用擔(dān)心會(huì)出 Bug,如果這個(gè)出 Bug 了那 Spring MVC 就沒(méi)法玩了。
try {
// 支持RestFul風(fēng)格API
// 采用Spring MVC內(nèi)置的匹配方式將當(dāng)前請(qǐng)求匹配到對(duì)應(yīng)的Controller Method上,獲取注解進(jìn)行匹配是否要加解密
HandlerExecutionChain handler = getHandler(request);
if (Objects.isNull(handler)) {
return false;
}
if (Objects.nonNull(handler.getHandler()) && handler.getHandler() instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler.getHandler();
String apiUri = RequestUriUtils.getApiUri(handlerMethod.getClass(), handlerMethod.getMethod(), request.getContextPath());
if (list.contains(apiUri)) {
return true;
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (Objects.isNull(dispatcherServlet)) {
return null;
}
if (dispatcherServlet.getHandlerMappings() != null) {
for (HandlerMapping mapping : dispatcherServlet.getHandlerMappings()) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
完整參考源碼:https://github.com/yinjihuan/monkey-api-encrypt/blob/master/monkey-api-encrypt-core/src/main/java/com/cxytiandi/encrypt/core/EncryptionFilter.java
新版本地址:https://search.maven.org/artifact/com.cxytiandi/monkey-api-encrypt-core/1.2.2.RELEASE/jar
總結(jié)
本文看似是在宣傳一個(gè)新功能,其實(shí)我想分享給大家的是 Restful 這種 API 的處理場(chǎng)景,除了本文中的場(chǎng)景,在其他場(chǎng)景下也會(huì)遇到類(lèi)似的問(wèn)題。比如我們?cè)谟?Cat 做埋點(diǎn)的時(shí)候,如果不做任何處理,Cat 上的地址信息就是訪問(wèn)的 uri,比如 /users/1, /users/2 這種,其實(shí)這 2 個(gè) uri 都是一個(gè)接口的請(qǐng)求,沒(méi)辦法歸類(lèi)。所以在埋點(diǎn)之前也需要將請(qǐng)求的 uri 轉(zhuǎn)換下格式。
關(guān)于作者:尹吉?dú)g,簡(jiǎn)單的技術(shù)愛(ài)好者,《Spring Cloud 微服務(wù)-全棧技術(shù)與案例解析》, 《Spring Cloud 微服務(wù) 入門(mén) 實(shí)戰(zhàn)與進(jìn)階》作者, 公眾號(hào)猿天地發(fā)起人。
后臺(tái)回復(fù) 學(xué)習(xí)資料 領(lǐng)取學(xué)習(xí)視頻
如有收獲,點(diǎn)個(gè)在看,誠(chéng)摯感謝
