Zuul作爲網關的其中一個重要功能,就是實現請求的鑑權。而這個動作我們往往是通過Zuul提供的過濾器來實現的。
1、過濾器
1.1 ZuulFilter
ZuulFilter是過濾器的頂級父類。在這裏我們看一下其中定義的4個最重要的方法:
public abstract ZuulFilter implements IZuulFilter{
abstract public String filterType();
abstract public int filterOrder();
boolean shouldFilter();// 來自IZuulFilter
Object run() throws ZuulException;// IZuulFilter
}
說明:
- shouldFilter:返回一個Boolean值,判斷該過濾器是否需要執行。返回true執行,返回false不執行。
- run:過濾器的具體業務邏輯。
- filterType:返回字符串,代表過濾器的類型。包含以下4種:
- pre:請求在被路由之前執行
- route:在路由請求時調用
- post:在route和errror過濾器之後調用
- error:處理請求時發生錯誤調用
- filterOrder:通過返回的int值來定義過濾器的執行順序,數字越小優先級越高。
1.2 過濾器執行生命週期
這張是Zuul官網提供的請求生命週期圖,清晰的表現了一個請求在各個過濾器的執行順序。
正常流程:
- 請求到達首先會經過pre類型過濾器,而後到達route類型,進行路由,請求就到達真正的服務提供者,執行請求,返回結果後,會到達post過濾器。而後返回響應。
異常流程:
- 整個過程中,pre或者route過濾器出現異常,都會直接進入error過濾器,在error處理完畢後,會將請求交給POST過濾器,最後返回給用戶。
- 如果是error過濾器自己出現異常,最終也會進入POST過濾器,將最終結果返回給請求客戶端。
- 如果是POST過濾器出現異常,會跳轉到error過濾器,但是與pre和route不同的是,請求不會再到達POST過濾器了。
所有內置過濾器列表:
1.3 使用場景
場景非常多:
- 請求鑑權:一般放在pre類型,如果發現沒有訪問權限,直接就攔截了
- 異常處理:一般會在error類型和post類型過濾器中結合來處理。
- 服務調用時長統計:pre和post結合使用。
2、自定義過濾器
接下來我們來自定義一個過濾器,模擬一個登錄的校驗。基本邏輯:如果請求中有access-token參數,則認爲請求有效,放行。
2.1 定義過濾器類
內容:
@Component
public class LoginFilter extends ZuulFilter {
/**
* 過濾器類型,前置過濾器
* @return
*/
@Override
public String filterType() {
return "pre";
}
/**
* 過濾器的執行順序
* @return
*/
@Override
public int filterOrder() {
return 1;
}
/**
* 該過濾器是否生效
* @return
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 登陸校驗邏輯
* @return
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
// 獲取zuul提供的上下文對象
RequestContext context = RequestContext.getCurrentContext();
// 從上下文對象中獲取請求對象
HttpServletRequest request = context.getRequest();
// 獲取token信息
String token = request.getParameter("access-token");
// 判斷
if (StringUtils.isBlank(token)) {
// 過濾該請求,不對其進行路由
context.setSendZuulResponse(false);
// 設置響應狀態碼,401
context.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);
// 設置響應信息
context.setResponseBody("{\"status\":\"401\", \"text\":\"request error!\"}");
}
// 校驗通過,把登陸信息放入上下文信息,繼續向後執行
context.set("token", token);
return null;
}
}
2.2 測試
沒有token參數時,訪問失敗:
添加token參數後: