上一篇文章中,講了Zuul 轉(zhuǎn)發(fā),動(dòng)態(tài)路由,負(fù)載均衡,等等一些Zuul 的特性,這個(gè)一篇文章,講Zuul Filter 使用,關(guān)于網(wǎng)關(guān)的作用,這里就不再次贅述了,重點(diǎn)是zuul的Filter ,我們可以實(shí)現(xiàn)安全控制,比如,只有請(qǐng)求參數(shù)中有token和密碼的客戶端才能訪問服務(wù)端的資源。那么如何來實(shí)現(xiàn)Filter了?
Zuul大部分功能都是通過過濾器來實(shí)現(xiàn)的。Zuul中定義了四種標(biāo)準(zhǔn)過濾器類型,這些過濾器類型對(duì)應(yīng)于請(qǐng)求的典型生命周期。
PRE:這種過濾器在請(qǐng)求被路由之前調(diào)用。我們可利用這種過濾器實(shí)現(xiàn)身份驗(yàn)證、在集群中選擇請(qǐng)求的微服務(wù)、記錄調(diào)試信息等。
ROUTING:這種過濾器將請(qǐng)求路由到微服務(wù)。這種過濾器用于構(gòu)建發(fā)送給微服務(wù)的請(qǐng)求,并使用Apache HttpClient或Netfilx Ribbon請(qǐng)求微服務(wù)。
OST:這種過濾器在路由到微服務(wù)以后執(zhí)行。這種過濾器可用來為響應(yīng)添加標(biāo)準(zhǔn)的HTTP Header、收集統(tǒng)計(jì)信息和指標(biāo)、將響應(yīng)從微服務(wù)發(fā)送給客戶端等。
ERROR:在其他階段發(fā)生錯(cuò)誤時(shí)執(zhí)行該過濾器。
除了默認(rèn)的過濾器類型,Zuul還允許我們創(chuàng)建自定義的過濾器類型。例如,我們可以定制一種STATIC類型的過濾器,直接在Zuul中生成響應(yīng),而不將請(qǐng)求轉(zhuǎn)發(fā)到后端的微服務(wù)。
我們先拿之前兩篇文章,構(gòu)建的兩個(gè)微服務(wù)代碼為基礎(chǔ),進(jìn)行下面的操作
建議先閱讀以下兩篇文章
Spring Cloud(四) 服務(wù)提供者 Eureka + 服務(wù)消費(fèi)者 Feign
Spring Cloud(三) 服務(wù)提供者 Eureka + 服務(wù)消費(fèi)者(rest + Ribbon)
http://www.ymq.io/2017/12/06/spring-cloud-feign/
http://www.ymq.io/2017/12/05/spring-cloud-ribbon-rest/
導(dǎo)入第三篇文章中的項(xiàng)目:作為服務(wù)注冊(cè)中心
spring-cloud-eureka-service
導(dǎo)入第三篇文章中的項(xiàng)目:作為服務(wù)的提供者
spring-cloud-eureka-provider-1
spring-cloud-eureka-provider-2
spring-cloud-eureka-provider-3
新建項(xiàng)目 spring-cloud-zuul-filter
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
在程序的啟動(dòng)類 ZuulFilterApplication
通過 @EnableZuulProxy
開啟 Zuul 服務(wù)網(wǎng)關(guān)
package io.ymq.example.zuul.filter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;
@EnableZuulProxy
@SpringBootApplication
public class ZuulFilterApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulFilterApplication.class, args);
}
}
配置文件 application.yml
spring:
application:
name: zuul-service-filter
server:
port: 9000
zuul:
routes:
api:
path: /**
serviceId: eureka-provider
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
ZuulFilter
是Zuul中核心組件,通過繼承該抽象類,覆寫幾個(gè)關(guān)鍵方法達(dá)到自定義調(diào)度請(qǐng)求的作用
TokenFilter 過濾器
package io.ymq.example.zuul.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
/**
* 描述: 過濾器 token
*
* @author yanpenglei
* @create 2017-12-11 14:38
**/
public class TokenFilter extends ZuulFilter {
private final Logger LOGGER = LoggerFactory.getLogger(TokenFilter.class);
@Override
public String filterType() {
return "pre"; // 可以在請(qǐng)求被路由之前調(diào)用
}
@Override
public int filterOrder() {
return 0; // filter執(zhí)行順序,通過數(shù)字指定 ,優(yōu)先級(jí)為0,數(shù)字越大,優(yōu)先級(jí)越低
}
@Override
public boolean shouldFilter() {
return true;// 是否執(zhí)行該過濾器,此處為true,說明需要過濾
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
LOGGER.info("--->>> TokenFilter {},{}", request.getMethod(), request.getRequestURL().toString());
String token = request.getParameter("token");// 獲取請(qǐng)求的參數(shù)
if (StringUtils.isNotBlank(token)) {
ctx.setSendZuulResponse(true); //對(duì)請(qǐng)求進(jìn)行路由
ctx.setResponseStatusCode(200);
ctx.set("isSuccess", true);
return null;
} else {
ctx.setSendZuulResponse(false); //不對(duì)其進(jìn)行路由
ctx.setResponseStatusCode(400);
ctx.setResponseBody("token is empty");
ctx.set("isSuccess", false);
return null;
}
}
}
ZuulFilter
是Zuul中核心組件,通過繼承該抽象類,覆寫幾個(gè)關(guān)鍵方法達(dá)到自定義調(diào)度請(qǐng)求的作用
PasswordFilter 過濾器
package io.ymq.example.zuul.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
/**
* 描述: 過濾器 Password
*
* @author yanpenglei
* @create 2017-12-11 15:40
**/
public class PasswordFilter extends ZuulFilter {
private final Logger LOGGER = LoggerFactory.getLogger(TokenFilter.class);
@Override
public String filterType() {
return "post"; // 請(qǐng)求處理完成后執(zhí)行的filter
}
@Override
public int filterOrder() {
return 1; // 優(yōu)先級(jí)為0,數(shù)字越大,優(yōu)先級(jí)越低
}
@Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
return (boolean) ctx.get("isSuccess");
// 判斷上一個(gè)過濾器結(jié)果為true,否則就不走下面過濾器,直接跳過后面的所有過濾器并返回 上一個(gè)過濾器不通過的結(jié)果。
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
LOGGER.info("--->>> PasswordFilter {},{}", request.getMethod(), request.getRequestURL().toString());
String username = request.getParameter("password");
if (null != username && username.equals("123456")) {
ctx.setSendZuulResponse(true);
ctx.setResponseStatusCode(200);
ctx.set("isSuccess", true);
return null;
} else {
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(400);
ctx.setResponseBody("The password cannot be empty");
ctx.set("isSuccess", false);
return null;
}
}
}
在程序的啟動(dòng)類 ZuulFilterApplication
添加 Bean
@Bean
public TokenFilter tokenFilter() {
return new TokenFilter();
}
@Bean
public PasswordFilter PasswordFilter() {
return new PasswordFilter();
}
filterType:返回一個(gè)字符串代表過濾器的類型,在zuul中定義了四種不同生命周期的過濾器類型,具體如下:
依次啟動(dòng)項(xiàng)目:
spring-cloud-eureka-service
spring-cloud-eureka-provider-1
spring-cloud-eureka-provider-2
spring-cloud-eureka-provider-3
spring-cloud-zuul-filter
啟動(dòng)該工程后,訪問服務(wù)注冊(cè)中心,查看服務(wù)是否都已注冊(cè)成功:http://localhost:8761/
查看 eureka 監(jiān)控,看服務(wù)是否都注冊(cè)成功
步驟一 提示 token is empty
步驟二 加上token ?token=token-uuid
,已經(jīng)驗(yàn)證通過了,提示 The password cannot be empty
訪問:http://127.0.0.1:9000/?token=token-uuid
![The password cannot be empty][3]
加上token
和 password
&password=123456
,已經(jīng)驗(yàn)證通過
訪問:http://127.0.0.1:9000/?token=token-uuid&password=123456
F5 刷新,每次都驗(yàn)證通過,并且負(fù)載均衡
GitHub:https://github.com/souyunku/spring-cloud-examples/tree/master/spring-cloud-zuul-filter
碼云:https://gitee.com/souyunku/spring-cloud-examples/tree/master/spring-cloud-zuul-filter
Wechat:關(guān)注公眾號(hào),搜云庫,專注于開發(fā)技術(shù)的研究與知識(shí)分享
更多建議: