Spring Cloud Gateway之路由断言工厂篇

1. 背景

最近,需要提升系统安全性,市面上有很多款网关服务的技术方案,最终选择了Spring Cloud Gateway

2. Spring Cloud Gateway工作机制

官网配图:

客户端向Spring Cloud Gateway发出请求。如果网关处理程序映射确定一个请求匹配一个路由,它将被发送到网关Web处理程序。此处理程序通过特定于请求的过滤器链运行请求。虚线分隔过滤器的原因是,过滤器可以在发送代理请求之前和之后运行逻辑。执行所有“预”筛选逻辑。然后发出代理请求。发出代理请求后,运行“post”筛选器逻辑。

注意:在没有端口的路由中定义的uri, HTTP和HTTPS uri的默认端口值分别为80443

2.1 路由断言工厂

Spring Cloud Gateway可以匹配各种路由,而其内部就包括许多内置的路由断言工厂。所有这些断言都匹配HTTP请求的不同属性。您可以将多个路由断言工厂与逻辑和语句组合在一起使用。

2.1.1 路由后断言工厂(The After Route Predicate Factory

路由后断言工厂可以接受一个datetime的时间参数。此断言匹配发生在指定日期时间之后的请求。配置示例如下:

spring:
  cloud:
    gateway:
      routes:
      - id: after_route   # 路由 Id,唯一
        uri: https://www.baidu.com    # 目标 URI, 路由到微服务的地址
        predicates:       # 断言(判断条件)
        - After=2022-01-20T17:42:47.789-07:00[America/Denver]     # 采用的是路由后断言工厂,配置时间

配置解读: 设置某个时间点,等当前时间在该条件之后就可以进行访问该路由,即访问该服务地址。

注意:

  • 如果有多个满足条件的after配置,则会路由到第一个uri。

  • 参数格式,满足ZonedDateTime格式,

2.1.2 路由前断言工厂(The Before Route Predicate Factory


路由断言工厂接受一个参数,即datetime。这个工厂其实跟前一个介绍的工厂效果恰恰是相反,也就是断言匹配发生在指定日期时间之前的请求。配置示例如下: 

spring:
  cloud:
    gateway:
      routes:
      - id: before_route   # 路由 Id,唯一
        uri: https://example.org      # 目标 URI, 路由到微服务的地址
        predicates:       # 断言(判断条件)
        - Before=2017-01-20T17:42:47.789-07:00[America/Denver]    # 使用路由前断言工厂,配置时间

配置解读: 设置某个时间点,等当前时间在该条件之前都可以进行访问该路由,即访问该服务地址。

2.1.3 间隔路由断言工厂(The Between Route Predicate Factory)

这个路由工厂的作用顾名思义就是设置在一个时间范围内允许访问该服务地址,配置事例如下:

spring:
  cloud:
    gateway:
      routes:
      - id: between_route   # 路由 Id,唯一
        uri: https://example.org      # 目标 URI, 路由到微服务的地址
        predicates:
        - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]      # 使用间隔路由断言工厂,配置时间范围

配置解读: 设置某个时间范围,等当前时间在该时间范围的条件之内都可以进行访问该路由,即访问该服务地址。

2.1.4 Cookie路由断言工厂(The Cookie Route Predicate Factory)

通过cookie和一个正则表达式作为断言条件的路由工厂,只要满足该条件就可以访问到该地址。

spring:
  cloud:
    gateway:
      routes:
      - id: between_route   # 路由 Id,唯一
        uri: https://example.org      # 目标 URI, 路由到微服务的地址
        predicates:
        - Cookie=chocolate, ch.p   # 使用Cookie路由断言工厂,配置cookie,正则表达式(可有可无)

配置解读:此路由将匹配具有一个名为chocolate的cookie的请求,该cookie的值匹配ch.p正则表达式。 

2.1.5 请求头路由断言工厂(The Header Route Predicate Factory

请求头路由断言工厂接受两个参数,报头名称和一个正则表达式。该断言与具有给定名称的头匹配,该名称的值与正则表达式匹配。下面的例子配置了:

spring:
  cloud:
    gateway:
      routes:
      - id: header_route
        uri: https://example.org
        predicates:
        - Header=X-Request-Id, \d+

配置解读:如果请求有一个名为X-Request-Id的请求头,其值匹配\d+正则表达式(也就是说,它有一个或多个数字的值),则此路由匹配。 

2.1.6 主机路由断言工厂(The Host Route Predicate Factory

主机路由断言工厂接受一个参数:主机名模式列表。该模式是一个ant样式的模式,通过 " . " 作为分隔符。这个断言匹配模式匹配的是Host头。配置示例如下:

spring:
  cloud:
    gateway:
      routes:
      - id: between_route   # 路由 Id,唯一
        uri: https://example.org      # 目标 URI, 路由到微服务的地址
        predicates:
        - Host=**.somehost.org,**.anotherhost.org     #使用主机路由断言工厂

配置解读:

URI模板变量(例如{sub}.myhost.org)也被支持。

如果请求的Host报头值为www.somehost.org或beta.somehost.org或www.anotherhost.org,则此路由匹配。

这个谓词提取URI模板变量(例如sub,在前面的例子中定义)作为名称和值的映射,并将其与在ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE中定义的键放在ServerWebExchange.getAttributes()中。这些值可以被GatewayFilter工厂使用。

2.1.7 方法路由断言工厂 (The Method Route Predicate Factory

方法路由断言工厂接受一个方法参数,它是一个或多个参数:要匹配的HTTP方法。配置示例如下:

spring:
  cloud:
    gateway:
      routes:
      - id: between_route   # 路由 Id,唯一
        uri: https://example.org      # 目标 URI, 路由到微服务的地址
        predicates:
        - Method=GET,POST    #使用方法路由断言工厂 

 配置解读:如果请求方法是GET或POST,则此路由匹配。

2.1.8 路径路由断言工厂(The Path Route Predicate Factory

路径路由断言工厂接受两个参数:一个Spring PathMatcher模式列表和一个名为matchTrailingSlash的可选标志(默认为true)。配置示例如下:

spring:
  cloud:
    gateway:
      routes:
      - id: between_route   # 路由 Id,唯一
        uri: https://example.org      # 目标 URI, 路由到微服务的地址
        predicates:
        - Path=/red/{segment},/blue/{segment}    #使用路径路由断言工厂

配置解读:

如果请求路径符合以上断言要求,则由该路由匹配,例如:  /red/1  或    /red/1/   或    /red/blue或     /blue/green。

如果将matchTrailingSlash设置为false,那么请求路径/red/1/将不会被匹配。

这个断言提取URI模板变量(例如在前面的例子中定义的segment)作为名称和值的映射,并将其与在ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE中定义的键放在ServerWebExchange.getAttributes()中。这些值可以被GatewayFilter工厂使用。

可以使用一个实用方法(称为get)来简化对这些变量的访问。下面的例子展示了如何使用get方法:

Map<String, String> uriVariables = ServerWebExchangeUtils.getPathPredicateVariables(exchange);

String segment = uriVariables.get("segment");

2.1.9 查询路由断言工厂 (The Query Route Predicate Factory

查询路由断言工厂接受两个参数:一个必需的参数和一个可选的regexp(它是一个Java正则表达式)。配置示例如下:

spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: https://example.org
        predicates:
        - Query=green

配置解读:如果请求包含green查询参数,则上述路由匹配。

spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: https://example.org
        predicates:
        - Query=red, gree.

 配置解读:如果请求中包含一个red的查询参数,且该参数的值匹配gree. 正则表达式(即green,gree2都是可以的),则上述路由匹配。,所以red和greet是匹配的。

2.1.10 远程地址路由断言工厂(The RemoteAddr Route Predicate Factory

远程地址路由断言工厂接受一个源列表(最小大小为1),它是 CIDR-notation (IPv4 or IPv6) ,例如192.168.0.1/16(其中192.168.0.1是一个IP地址,16是一个子网掩码)。配置示例如下:

spring:
  cloud:
    gateway:
      routes:
      - id: remoteaddr_route
        uri: https://example.org
        predicates:
        - RemoteAddr=192.168.1.1/24

配置解读:如果请求的远端地址是,例如192.168.1.10,则此路由匹配。

  1. 修改远端地址解析方式

默认情况下,远程地址路由断言工厂使用来自传入请求的远程地址。如果Spring Cloud Gateway位于代理层后面,这可能与实际的客户端IP地址不匹配。 

你可以通过设置一个自定义的RemoteAddressResolver来自定义远程地址解析的方式。Spring Cloud Gateway提供了一个非默认的远程地址解析器,它基于X-Forwarded-For报头,即XForwardedRemoteAddressResolver。

XForwardedRemoteAddressResolver有两个静态构造函数方法,它们采用不同的安全方法:

  • XForwardedRemoteAddressResolver::trustAll返回一个RemoteAddressResolver,它总是采用X-Forwarded-For头中发现的第一个IP地址。这种方法很容易受到欺骗,因为恶意客户端可能会为X-Forwarded-For设置初始值,解析器将接受该初始值。
  • XForwardedRemoteAddressResolver::maxTrustedIndex获取一个与Spring Cloud Gateway前面运行的可信基础设施数量相关的索引。例如,如果Spring Cloud Gateway只能通过HAProxy访问,那么应该使用值1。如果在访问Spring Cloud Gateway之前需要信任基础设施的两个跃点,那么应该使用值2。

考虑以下报头值:

X-Forwarded-For: 0.0.0.1, 0.0.0.2, 0.0.0.3

 下面的maxTrustedIndex值产生以下远程地址:

下面的例子展示了如何用Java实现相同的配置:

RemoteAddressResolver resolver = XForwardedRemoteAddressResolver
    .maxTrustedIndex(1);

...

.route("direct-route",
    r -> r.remoteAddr("10.1.1.1", "10.10.1.1/24")
        .uri("https://downstream1")
.route("proxied-route",
    r -> r.remoteAddr(resolver, "10.10.1.1", "10.10.1.1/24")
        .uri("https://downstream2")
)

2.1.11 权重路由断言工厂(The Weight Route Predicate Factory

权重路由断言工厂接受两个参数:group和Weight(一个int类型)。权重按每组计算。配置示例如下:

spring:
  cloud:
    gateway:
      routes:
      - id: weight_high
        uri: https://weighthigh.org
        predicates:
        - Weight=group1, 8
      - id: weight_low
        uri: https://weightlow.org
        predicates:
        - Weight=group1, 2

 配置解读:将把80%的流量转发到weighthigh.org, 20%的流量转发到weighlow.org

2.1.12  The XForwarded 远程地址路由断言工厂(The XForwarded Remote Addr Route Predicate Factory

The XForwarded 远程地址路由断言工厂接受一个源列表(最小大小为1),它它是 CIDR-notation (IPv4 or IPv6) ,例如192.168.0.1/16(其中192.168.0.1是一个IP地址,16是一个子网掩码)。

这个路由断言允许基于X-Forwarded-For HTTP头对请求进行过滤。 

这可以用于反向代理,如负载均衡器或web应用程序防火墙,在这些反向代理中,只有当请求来自由这些反向代理使用的可信IP地址列表时,才应该允许该请求。

配置示例如下:

spring:
  cloud:
    gateway:
      routes:
      - id: xforwarded_remoteaddr_route
        uri: https://example.org
        predicates:
        - XForwardedRemoteAddr=192.168.1.1/24

配置解读:如果X-Forwarded-For报头包含192.168.1.10,则此路由匹配。

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值