Zuul 自定义过滤器

**Zuul 的核心技术就是过滤器,该框架提供了 ZuulFilter 接口让开发者可以自定义过滤规则。

我们以身份检验为例,自定义 ZuulFilter 过滤器实现该功能。**

创建用户服务

新建名为 user-server 的项目。

添加依赖:

<!-- common api -->
<dependency>
  <groupId>com.extlight.springcloud</groupId>
  <artifactId>common-api</artifactId>
  <version>${parent-version}</version>
</dependency>
  	
<!-- springmvc -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- eureka 客户端 -->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

application.yml:

server:
    port: 8200

spring:
  application:
    name: USER
    
eureka:
    instance:
        instance-id: user-api-8200
        prefer-ip-address: true # 访问路径可以显示 IP
    client:
        service-url:
            defaultZone: http://localhost:9000/eureka/  # 注册中心访问地址

登录接口:

@RestController
@RequestMapping("/user")
public class LoginController {

	@PostMapping("/login")
	public Result login(String username, String password, HttpServletResponse response) {
		
		
		if ("admin".equals(username) && "admin".equals(password)) {
			// 模拟生成 token,实际开发中 token 应存放在数据库或缓存中
			String token = "123456";
			Cookie cookie = new Cookie("token", token);
			cookie.setPath("/");
			cookie.setMaxAge(60 * 10);
			response.addCookie(cookie);
			
			return Result.success();
		}
		
		return Result.fail(401, "账号或密码错误");
	}
}

user-server 启动类:

@EnableEurekaClient
@SpringBootApplication
public class UserServerApplication {

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

创建 ZuulFilter 过滤器

在 gateway-server 项目中,新建一个过滤器,需要继承 ZuulFilter 类:

@Component
public class AuthenticationFilter extends ZuulFilter {

	/**
	 * 是否开启过滤
	 */
	@Override
	public boolean shouldFilter() {
		RequestContext context = RequestContext.getCurrentContext();
        HttpServletRequest request = context.getRequest();
        
		boolean flag = request.getRequestURI().contains("/login");
		// 如果是登录请求不进行过滤
		if (flag) {
			System.out.println("========不执行 zuul 过滤方法=======");
		} else {
			System.out.println("========执行 zuul 过滤方法=======");
		}
		return !flag;
	}

	/**
	 * 过滤器执行内容
	 */
	@Override
	public Object run() throws ZuulException {
		
		RequestContext context = RequestContext.getCurrentContext();
        HttpServletRequest request = context.getRequest();
        String token = request.getParameter("token");
        // 此处模拟获取数据库或缓存中的 token
        String dbToken = "123456";
        // 此处简单检验 token
        if (token == null || "".equals(token) || !dbToken.equals(token)) {
        	context.setSendZuulResponse(false);
        	context.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
        }
        
		return null;
	}

	/**
	 * 过滤器类型
	 */
	@Override
	public String filterType() {
		return "pre";
	}

	/**
	 * 过滤器执行顺序
	 */
	@Override
	public int filterOrder() {
		return 0;
	}

}

其中,filterType 有 4 种类型:

pre: 这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。

routing:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用 Apache HttpClient 或 Netfilx Ribbon 请求微服务。

post:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的 HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。

error:在其他阶段发生错误时执行该过滤器。

zuul-04

运行所有项目,测试操作步骤如下:

请求用户服务的登录接口(http://localhost:9600/user/user/login),请求不执行 zuul 过滤方法,并且请求响应返回的 cookie 包含 token

请求订单服务的下单接口(http://localhost:9600/extlight/order/place),但不携带 token,请求需要执行 zuul 过滤方法,请求响应 401 权限不足

请求订单服务的下单接口(http://localhost:9600/extlight/order/place),携带之前登录接口返回的 token,请求需要执行 zuul 过滤方法,校验通过后路由到订单服务执行之后的操作

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×