Zuul 过滤器

Zuul 过滤器

薛定谔的汪

前面学习了 Zuul 的一些特性和基本使用,包括请求转发,负载均衡等,前面也提到 Zuul 还可以用来做过滤权限、记录API日志等功能,其实这些都是基于 ZuulFilter 过滤器来实现的,今天对学习 ZuulFilter 做一个总结。

如何利用 ZuulFilter 实现权限控制?

Zuul 过滤器

首先看下官方的 Zuul 执行流程图

结合官方文档和流程图,得出Filter 是 Zuul 的核心,实现了对外部请求的控制。ZuulFilter 有四种,代表了 Zuul 中 filter 的四个生命周期

  • PRE: 这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
  • ROUTING:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用Apache HttpClient或Netfilx Ribbon请求微服务。
  • POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
  • ERROR:在其他阶段发生错误时执行该过滤器。 除了默认的过滤器类型,Zuul还允许我们创建自定义的过滤器类型。例如,我们可以定制一种STATIC类型的过滤器,直接在Zuul中生成响应,而不将请求转发到后端的微服务。

我们可以自定义 Filter,来让 Zuul 具有我们想要的功能,zuul过滤器是链型。

代码示例

让 zuul 模拟登录功能,只有携带特定token标识的用户才可以执行登录。

继续需用之前的 eureka-server 和 eureka-provider 作为注册中心和服务提供者。

新建 SpringBoot 项目,名称为 zuul-filter

依赖

1
2
3
4
5
6
7
8
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>

配置文件

1
2
3
4
5
6
7
8
9
spring:
application:
name: zuul-test
server:
port: 8888
eureka:
client:
service-url:
defaultZone: http://localhost:8000/eureka/

自定义Zuul过滤器类

CustomTokenFilter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class CustomTokenFilter extends ZuulFilter {

@Override
public String filterType() {
//生命周期是 pre 过滤器
return "pre";
}

@Override
public int filterOrder() {
//过滤器有优先级,越小越先执行
return 0;
}

@Override
public boolean shouldFilter() {
//是否启动此过滤器
return true;
}

@Override
public Object run() throws ZuulException {
//过滤器执行的逻辑
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
String token = request.getParameter("token");
if(StringUtils.isNotBlank(token)){
//token 不为空 转发请求 放行至下一个filter 或目标服务
requestContext.setSendZuulResponse(true);
requestContext.setResponseStatusCode(200);
requestContext.set("success",true);
}else{
requestContext.setSendZuulResponse(false);
requestContext.setResponseBody("no token!!");
requestContext.setResponseStatusCode(400);
requestContext.set("success",false);
}
return null;
}
}
CustomLoginFilter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public class CustomLoginFilter extends ZuulFilter {
@Override
public String filterType() {
return "pre";
}

@Override
public int filterOrder() {
//先执行 CustomTokenFilter,通过后再执行CustomLoginFilter
return 1;
}

@Override
public boolean shouldFilter() {
RequestContext requestContext = RequestContext.getCurrentContext();
Object successObj = requestContext.get("success");
if(successObj instanceof Boolean){
//上一个 CustomTokenFilter 执行通过了再执行此过滤器
return (boolean)successObj;
}
return false;
}

@Override
public Object run() throws ZuulException {
//判断用户账号密码是否正确
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
String username = request.getParameter("username");
String password = request.getParameter("password");
if("admin".equals(username) && "123456".equals(password)){
requestContext.setSendZuulResponse(true);
requestContext.setResponseStatusCode(200);
requestContext.set("success",true);
}else{
requestContext.setSendZuulResponse(false);
requestContext.setResponseBody("username or password is error!");
requestContext.setResponseStatusCode(400);
requestContext.set("success",false);
}
return null;
}
}

启动类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@SpringBootApplication
@EnableZuulProxy
public class ZuulFilterApplication {

public static void main(String[] args) {
SpringApplication.run(ZuulFilterApplication.class, args);
}

@Bean
public CustomTokenFilter tokenFilter(){
return new CustomTokenFilter();
}

@Bean
public CustomLoginFilter loginFilter(){
return new CustomLoginFilter();
}
}

这里写了两个过滤器,一个是判断 token 是否为空,只有当 token 不为空时才可以执行下一个过滤器,判断用户名和密码是否正确,正确才去访问 provider 服务的接口。

测试

启动 eureka-server,eureka-provider,zuul-filter 项目

浏览器输入http://localhost:8888/provider/hello,页面显示:

no token!!

浏览器输入http://localhost:8888/provider/hello?token=a,页面显示:

username or password is error!

浏览器输入http://localhost:8888/provider/hello?token=a&username=admin&password=123456,页面显示:

hello! Yakai! from provider

说明 Zuul 的执行过滤器链成功!

以上代码测试对 ZuulFilter 有了基本的应用,在实际开发中可根据业务需要,自定义各种 Filter 进行不同的业务处理、甚至可以自定义不限于“PRE”、“ROUTING”、“POST”、”ERROR”的过滤器类型。

  • Title: Zuul 过滤器
  • Author: 薛定谔的汪
  • Created at : 2018-06-16 18:20:16
  • Updated at : 2023-11-17 19:37:36
  • Link: https://www.zhengyk.cn/2018/06/16/springcloud/zuul-02/
  • License: This work is licensed under CC BY-NC-SA 4.0.
On this page
Zuul 过滤器