Spring Cloud Gateway除了具備請求路由功能之外,也支持對請求的過濾。通過Zuul網關類似,也是通
過過濾器的形式來實現的。那么接下來我們一起來研究一下Gateway中的過濾器
3.3.1 過濾器基礎
(1) 過濾器的生命周期
Spring Cloud Gateway 的 Filter 的生命周期不像 Zuul 的那么豐富,它只有兩個:“pre” 和 “post”。
PRE : 這種過濾器在請求被路由之前調用。我們可利用這種過濾器實現身份驗證、在集群中選擇
請求的微服務、記錄調試信息等。
POST :這種過濾器在路由到微服務以后執行。這種過濾器可用來為響應添加標准的 HTTP
Header、收集統計信息和指標、將響應從微服務發送給客戶端等。
( 2) 過濾器類型
Spring Cloud Gateway 的 Filter 從作用范圍可分為另外兩種GatewayFilter 與 GlobalFilter。
GatewayFilter :應用到單個路由或者一個分組的路由上。
GlobalFilter :應用到所有的路由上。
3.3.2 局部過濾器
局部過濾器(GatewayFilter),是針對單個路由的過濾器。可以對訪問的URL過濾,進行切面處理。在
Spring Cloud Gateway中通過GatewayFilter的形式內置了很多不同類型的局部過濾器。這里簡單將
Spring Cloud Gateway內置的所有過濾器工廠整理成了一張表格,雖然不是很詳細,但能作為速覽使
用。如下:
每個過濾器工廠都對應一個實現類,並且這些類的名稱必須以 GatewayFilterFactory 結尾,這是
Spring Cloud Gateway的一個約定,例如 AddRequestHeader 對應的實現類為
AddRequestHeaderGatewayFilterFactory 。對於這些過濾器的使用方式可以參考官方文檔
3.3.3 全局過濾器
全局過濾器(GlobalFilter)作用於所有路由,Spring Cloud Gateway 定義了Global Filter接口,用戶
可以自定義實現自己的Global Filter。通過全局過濾器可以實現對權限的統一校驗,安全性驗證等功
能,並且全局過濾器也是程序員使用比較多的過濾器。
Spring Cloud Gateway內部也是通過一系列的內置全局過濾器對整個路由轉發進行處理如下:
3.4 統一鑒權
內置的過濾器已經可以完成大部分的功能,但是對於企業開發的一些業務功能處理,還是需要我們自己
編寫過濾器來實現的,那么我們一起通過代碼的形式自定義一個過濾器,去完成統一的權限校驗。
3.4.1 鑒權邏輯
開發中的鑒權邏輯:
當客戶端第一次請求服務時,服務端對用戶進行信息認證(登錄)
認證通過,將用戶信息進行加密形成 token,返回給客戶端,作為登錄憑證
以后每次請求,客戶端都攜帶認證的 token
服務端對 token進行解密,判斷是否有效。
如上圖,對於驗證用戶是否已經登錄鑒權的過程可以在網關層統一檢驗。檢驗的標准就是請求中是否攜
帶token憑證以及token的正確性。
3.4.2 代碼實現
下面的我們自定義一個GlobalFilter,去校驗所有請求的請求參數中是否包含“token”,如何不包含請求
參數“token”則不轉發路由,否則執行正常的邏輯。
/** * 自定義一個全局過濾器 * 實現 globalfilter , ordered接口 */ @Component public class LoginFilter implements GlobalFilter,Ordered { /** * 執行過濾器中的業務邏輯 * 對請求參數中的access-token進行判斷 * 如果存在此參數:代表已經認證成功 * 如果不存在此參數 : 認證失敗. * ServerWebExchange : 相當於請求和響應的上下文(zuul中的RequestContext) */ @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { System.out.println("執行了自定義的全局過濾器"); //1.獲取請求參數access-token String token = exchange.getRequest().getQueryParams().getFirst("access-token"); //2.判斷是否存在 if(token == null) { //3.如果不存在 : 認證失敗 System.out.println("沒有登錄"); exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); return exchange.getResponse().setComplete(); //請求結束 } //4.如果存在,繼續執行 return chain.filter(exchange); //繼續向下執行 } /** * 指定過濾器的執行順序 , 返回值越小,執行優先級越高 */ @Override public int getOrder() { return 0; } }