本文主要介绍 RuoYi 中用到的过滤器,以及过滤器原理简单分析。Spring Gateway 的详细原理请参考作者另外的文章。

1. 网关的过滤器清单

在“网关模块”一共定义了5个过滤器。分类如下:

  • 继承AbstractGatewayFilterFactory的

    • ValidateCodeFilter(验证码过滤器)
    • BlackListUrlFilter(黑名单过滤器)
    • CacheRequestFilter
  • 实现GlobalFilter, Ordered接口

    • XssFilter(跨站脚本过滤器)
    • AuthFilter(网关鉴权)

2. GatewayFilterFactory和GlobalFilter 的原理

有以下几个问题需要解决

  • 继承 AbstractGatewayFilterFactory 类和实现 GlobalFilter, Ordered 接口 2 种方式的过滤器有什么不同?

GlobalFilter 参考:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-combined-global-filter-and-gatewayfilter-ordering

GatewayFilterFactory参考:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gatewayfilter-factories

关键是:GlobalFilter 针对“所有路由”,而 GatewayFilterFactory 针对“特定路由

  • 为什么实现 Spring 的 Ordered 接口

为了控制过滤器的顺序,Spring 的 Ordered 接口是根据 order 值升序排序的。

  • 既有继承又有实现接口,它们的顺序是怎么样的
public Mono<Void> handle(ServerWebExchange exchange) {
    Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
    List<GatewayFilter> gatewayFilters = route.getFilters();

    List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
    combined.addAll(gatewayFilters);
    // TODO: needed or cached?
    AnnotationAwareOrderComparator.sort(combined);

    if (logger.isDebugEnabled()) {
        logger.debug("Sorted gatewayFilterFactories: " + combined);
    }

    return new DefaultGatewayFilterChain(combined).filter(exchange);
}

从以上 combine 可以看到先从请求 request 属性中获取了特定路由的过滤器gatewayFilters,在结合全局过滤器combined,最后经过 Ordered 排序。但是继承GatewayFilterFactory并没有指定 order 的值,只有实现 Ordered 接口才指定了 order 值,此时怎么处理GatewayFilterFactory的???

猜测:是不是跟 nacos 的网关 route 配置的 filters 的顺序有关呢。

结论:猜测正确✅

3. RuoYi网关的配置文件是如何配置的

  • 各个服务的路由配置是怎么样的(特别是 auth 认证服务)

在 nacos 的网关配置文件 ruoyi-gateway-dev.yml 中给 ruoyi-auth 模块多配置了几个过滤器 filter。

spring:
  redis:
    host: localhost
    port: 6379
    password:
  cloud:
    gateway:
      discovery:
        locator:
          lowerCaseServiceId: true
          enabled: true
      routes:
        # 认证中心
        - id: ruoyi-auth
          uri: lb://ruoyi-auth
          predicates:
            - Path=/auth/**
          filters:
            # 验证码处理
            - CacheRequestFilter
            - ValidateCodeFilter
            - StripPrefix=1
        # 代码生成
        - id: ruoyi-gen
          uri: lb://ruoyi-gen
          predicates:
            - Path=/code/**
          filters:
            - StripPrefix=1
        # 定时任务
        - id: ruoyi-job
          uri: lb://ruoyi-job
          predicates:
            - Path=/schedule/**
          filters:
            - StripPrefix=1
        # 系统模块
        - id: ruoyi-system
          uri: lb://ruoyi-system
          predicates:
            - Path=/system/**
          filters:
            - StripPrefix=1
        # 文件服务
        - id: ruoyi-file
          uri: lb://ruoyi-file
          predicates:
            - Path=/file/**
          filters:
            - StripPrefix=1

# 安全配置
security:
  # 验证码
  captcha:
    enabled: true
    type: math
  # 防止XSS攻击
  xss:
    enabled: true
    excludeUrls:
      - /system/notice
  # 不校验白名单
  ignore:
    whites:
      - /auth/logout
      - /auth/login
      - /auth/register
      - /*/v2/api-docs
      - /csrf

其中给Auth模块特别配置了CacheRequestFilter、ValidateCodeFilter。其它模块全局使用了XssFilter、AuthFilter过滤器

  • 如果有多个过滤器,那么执行顺序是怎么样的。

全局的过滤器globalFilters是可以定义order值的,不能定义orderd值的局部过滤器(跟特定路由绑定)是依据 yml 配置文件配置的顺序(先配置的orderd值是1,递增的)。所以 yml 配置中只配置跟路由相关的局部过滤器。

  • auth 服务的有哪些过滤器

结合gatewayFilters是按照配置文件的顺序(order是1,2,3依次递增),globalFilters也是按照order的顺序排序。所以对于RuoYi的过滤器来说顺序是:

AuthFilter(order=-200)
XssFilter(order=-100)
CacheRequestFilter(order=1)
ValidateCodeFilter(order=2)
StripPrefix(order=3)

4. 资料参考

语雀笔记地址:https://www.yuque.com/yuchangyuan/tkb5br

4.1. 过滤器顺序的原理

1、先找到断言处理器的映射规则类RoutePredicateHandlerMapping

2、该类的getHandlerInternal方法中的lookupRoute方法会决定采用哪一个route,并设置到request属性中

3、然后是FilteringWebHandler的handler方法

4、handler方法中获取到route的gatewayFilters和全局的globalFilters,然后按照order升序排序。img

猜测route的gatewayFilters的order属性1,2,3是不是按照配置中心配置排序的。改变下配置中心的配置重新debug观察下。(猜测正确)

Logo

基于 Vue 的企业级 UI 组件库和中后台系统解决方案,为数万开发者服务。

更多推荐