Spring Cloud(七)服務網關 Zuul Filter 使用

上一篇文章中,講了Zuul 轉發,動態路由,負載均衡,等等一些Zuul 的特性,這個一篇文章,講Zuul Filter 使用,關於網關的作用,這裡就不再次贅述了,重點是zuul的Filter ,我們可以實現安全控制,比如,只有請求參數中有token和密碼的客戶端才能訪問服務端的資源。那麼如何來實現Filter了?

Spring Cloud Zuul

zuul 執行流程

Zuul大部分功能都是通過過濾器來實現的。Zuul中定義了四種標準過濾器類型,這些過濾器類型對應於請求的典型生命周期。

**PRE:**這種過濾器在請求被路由之前調用。我們可利用這種過濾器實現身份驗證、在集群中選擇請求的微服務、記錄調試信息等。

**ROUTING:**這種過濾器將請求路由到微服務。這種過濾器用於構建發送給微服務的請求,並使用Apache HttpClient或Netfilx Ribbon請求微服務。

**OST:**這種過濾器在路由到微服務以後執行。這種過濾器可用來為響應添加標準的HTTP Header、收集統計信息和指標、將響應從微服務發送給客戶端等。

**ERROR:**在其他階段發生錯誤時執行該過濾器。

除了默認的過濾器類型,Zuul還允許我們創建自定義的過濾器類型。例如,我們可以定製一種STATIC類型的過濾器,直接在Zuul中生成響應,而不將請求轉發到後端的微服務。

準備工作

我們先拿之前兩篇文章,構建的兩個微服務代碼為基礎,進行下面的操作

建議先閱讀以下兩篇文章

Spring Cloud(四) 服務提供者 Eureka + 服務消費者 Feign Spring Cloud(三) 服務提供者 Eureka + 服務消費者(rest + Ribbon)

ymq.io/2017/12/06/sprin

ymq.io/2017/12/05/sprin

Eureka Service

導入第三篇文章中的項目:作為服務註冊中心

spring-cloud-eureka-service

Eureka Provider

導入第三篇文章中的項目:作為服務的提供者

spring-cloud-eureka-provider-1 spring-cloud-eureka-provider-2 spring-cloud-eureka-provider-3

簡單使用

新建項目 spring-cloud-zuul-filter

添加依賴

<dependency>nt<groupId>org.springframework.cloud</groupId>nt<artifactId>spring-cloud-starter-zuul</artifactId>n</dependency>n

開啟服務註冊

在程序的啟動類 ZuulFilterApplication 通過 @EnableZuulProxy 開啟 Zuul 服務網關

package io.ymq.example.zuul.filter;nnimport org.springframework.boot.SpringApplication;nimport org.springframework.boot.autoconfigure.SpringBootApplication;nimport org.springframework.cloud.netflix.zuul.EnableZuulProxy;nimport org.springframework.context.annotation.Bean;nn@EnableZuulProxyn@SpringBootApplicationnpublic class ZuulFilterApplication {nn public static void main(String[] args) {n SpringApplication.run(ZuulFilterApplication.class, args);n }n}n

添加配置

配置文件 application.yml

spring:n application:n name: zuul-service-filternnserver:n port: 9000nnzuul:n routes:n api:n path: /**n serviceId: eureka-providernneureka:n client:n serviceUrl:n defaultZone: http://localhost:8761/eureka/n

TokenFilter

ZuulFilter 是Zuul中核心組件,通過繼承該抽象類,覆寫幾個關鍵方法達到自定義調度請求的作用

TokenFilter 過濾器

package io.ymq.example.zuul.filter;nnimport com.netflix.zuul.ZuulFilter;nimport com.netflix.zuul.context.RequestContext;nimport org.apache.commons.lang.StringUtils;nimport org.slf4j.Logger;nimport org.slf4j.LoggerFactory;nnimport javax.servlet.http.HttpServletRequest;nn/**n * 描述: 過濾器 tokenn *n * @author yanpenglein * @create 2017-12-11 14:38n **/npublic class TokenFilter extends ZuulFilter {nn private final Logger LOGGER = LoggerFactory.getLogger(TokenFilter.class);nn @Overriden public String filterType() {n return "pre"; // 可以在請求被路由之前調用n }nn @Overriden public int filterOrder() {n return 0; // filter執行順序,通過數字指定 ,優先順序為0,數字越大,優先順序越低n }nn @Overriden public boolean shouldFilter() {n return true;// 是否執行該過濾器,此處為true,說明需要過濾n }nn @Overriden public Object run() {n RequestContext ctx = RequestContext.getCurrentContext();n HttpServletRequest request = ctx.getRequest();nn LOGGER.info("--->>> TokenFilter {},{}", request.getMethod(), request.getRequestURL().toString());nn String token = request.getParameter("token");// 獲取請求的參數nn if (StringUtils.isNotBlank(token)) {n ctx.setSendZuulResponse(true); //對請求進行路由n ctx.setResponseStatusCode(200);n ctx.set("isSuccess", true);n return null;n } else {n ctx.setSendZuulResponse(false); //不對其進行路由n ctx.setResponseStatusCode(400);n ctx.setResponseBody("token is empty");n ctx.set("isSuccess", false);n return null;n }n }nn}n

PasswordFilter

ZuulFilter 是Zuul中核心組件,通過繼承該抽象類,覆寫幾個關鍵方法達到自定義調度請求的作用

PasswordFilter 過濾器

package io.ymq.example.zuul.filter;nnimport com.netflix.zuul.ZuulFilter;nimport com.netflix.zuul.context.RequestContext;nimport org.slf4j.Logger;nimport org.slf4j.LoggerFactory;nnimport javax.servlet.http.HttpServletRequest;nn/**n * 描述: 過濾器 Passwordn *n * @author yanpenglein * @create 2017-12-11 15:40n **/npublic class PasswordFilter extends ZuulFilter {nn private final Logger LOGGER = LoggerFactory.getLogger(TokenFilter.class);nn @Overriden public String filterType() {n return "post"; // 請求處理完成後執行的filtern }nn @Overriden public int filterOrder() {n return 1; // 優先順序為0,數字越大,優先順序越低n }nn @Overriden public boolean shouldFilter() {n RequestContext ctx = RequestContext.getCurrentContext();n return (boolean) ctx.get("isSuccess");n // 判斷上一個過濾器結果為true,否則就不走下面過濾器,直接跳過後面的所有過濾器並返回 上一個過濾器不通過的結果。n }nn @Overriden public Object run() {n RequestContext ctx = RequestContext.getCurrentContext();n HttpServletRequest request = ctx.getRequest();nn LOGGER.info("--->>> PasswordFilter {},{}", request.getMethod(), request.getRequestURL().toString());nn String username = request.getParameter("password");n if (null != username && username.equals("123456")) {n ctx.setSendZuulResponse(true);n ctx.setResponseStatusCode(200);n ctx.set("isSuccess", true);n return null;n } else {n ctx.setSendZuulResponse(false);n ctx.setResponseStatusCode(400);n ctx.setResponseBody("The password cannot be empty");n ctx.set("isSuccess", false);n return null;n }n }n}n

開啟過濾器

在程序的啟動類 ZuulFilterApplication 添加 Bean

@Beannpublic TokenFilter tokenFilter() {ntreturn new TokenFilter();n}nn@Beannpublic PasswordFilter PasswordFilter() {ntreturn new PasswordFilter();n}n

filterType

filterType:返回一個字元串代表過濾器的類型,在zuul中定義了四種不同生命周期的過濾器類型,具體如下:

  • pre:路由之前
  • routing:路由之時
  • post: 路由之後
  • error:發送錯誤調用
  • filterOrder:過濾的順序
  • shouldFilter:這裡可以寫邏輯判斷,是否要過濾,本文true,永遠過濾。
  • run:過濾器的具體邏輯。可用很複雜,包括查sql,nosql去判斷該請求到底有沒有許可權訪問。

測試服務

依次啟動項目:

spring-cloud-eureka-service spring-cloud-eureka-provider-1 spring-cloud-eureka-provider-2 spring-cloud-eureka-provider-3 spring-cloud-zuul-filter

啟動該工程後,訪問服務註冊中心,查看服務是否都已註冊成功:localhost:8761/

查看 eureka 監控,看服務是否都註冊成功

token 測試

訪問:127.0.0.1:8761/

步驟一 提示 token is empty

訪問:127.0.0.1:9000/

步驟二 加上token ?token=token-uuid ,已經驗證通過了,提示 The password cannot be empty

訪問:127.0.0.1:9000/?

password 測試

加上tokenpassword &password=123456 ,已經驗證通過

訪問:http://127.0.0.1:9000/?token=token-uuid&password=123456

F5 刷新,每次都驗證通過,並且負載均衡

源碼下載

GitHub:github.com/souyunku/spr

碼云:gitee.com/souyunku/spri

Contact

  • 作者:鵬磊
  • 出處:http://www.ymq.io
  • Email:admin@souyunku.com
  • 版權歸作者所有,轉載請註明出處
  • Wechat:關注公眾號,搜雲庫,專註於開發技術的研究與知識分享

weixin.qq.com/r/0UwmPsn (二維碼自動識別)

推薦閱讀:

如何評價華為新開源的ServiceComb微服務框架?

TAG:SpringCloud | 微服务架构 |