• 【RuoYi项目分析】介绍RuoYi网关的过滤器



    本文主要介绍 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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    从以上 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
    
    • 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
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    其中给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)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    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观察下。(猜测正确)

  • 相关阅读:
    如何从 FastReport VCL 中将报表导出为PNG格式?
    [计算机网络] 选择判断查缺补漏
    简单说说量化交易接口有哪些用途?
    Vue3的异步组件使用
    Java学习笔记2024/2/23
    scrapy案例教程
    HashSet和LinkedHashSet
    基于微信小程序的垃圾分类系统,附源码
    java绘图技术基础
    【设计模式】七大设计原则
  • 原文地址:https://blog.csdn.net/yuchangyuan5237/article/details/133473123