Portal-Gateway路由网关

1.1整体设计

 

  • Portal-Gateway的应用场景:用户已登录,请求其他服务。
  • 客户端的请求到达网关,网关会调用gateway系统进行请求身份合法性的验证:
  1. 验证不通则直接拒绝,并返回401;
  2. 如果通过验证,则转发到具体服务。

Portal-Gateway的架构图如下所示:

Portal-Gateway路由网关


1.2 gateway实现

主要实现的功能有:

    • 区分暴露接口(即对外直接访问)和需要合法身份登录之后才能访问的接口
    • 需要合法身份登录之后才能访问的接口,根据传入的Access token进行构造头部,头部主要包括userId等信息,可根据自己的实际业务在auth服务中进行设置。
    • 需要暴露接口设置permitAll(),其余接口进入身份合法性校验的流程,调用auth服务,如果通过则正常继续转发,否则抛出异常,返回401。

绘制的流程图如下:

Portal-Gateway路由网关


1.2.1 permitAll实现

对外暴露的接口可以直接访问,这可以依赖配置文件,而配置文件又可以通过配置中心进行动态更新,所以不用担心有hard-code的问题。经过permitall配置的路径

在配置文件中定义需要permitall的路径:

 

auth:
  permitall:
    -
      pattern: /login/**
    -
      pattern: /web/public/**

 

 

服务启动时,读入相应的Configuration,下面的配置属性读取以auth开头的配置:

 

@Bean
@ConfigurationProperties(prefix = "auth")
public PermitAllUrlProperties getPermitAllUrlProperties() {
    return new PermitAllUrlProperties();
}

 


1.2.2 自定义RemoteTokenServices实现

ResourceServerTokenServices接口其中的一个实现是RemoteTokenServices

RemoteTokenServices主要是查询auth服务的/check_token端点以获取一个token的校验结果。如果有错误,则说明token是不合法的。Spring Cloud Security添加如下默认配置,对应auth服务中的相应端点。

 

properties: 
    sso: 
        loginUrl: https://myrtc.egoonet.com/sso    # 单点登录地址  
        ssoInternal: https://myrtc.egoonet.com/sso # 单点中心内网负载地址,SAML协议可不填
    security:
        oauth2:
          client:
              client-id: portal                    # 客户端ID (单点中心提供)      
              client-secret: oauth_client_secret   # 客户端秘钥 (单点中心提供)     
          resource:
              user-info-uri: ${properties.sso.loginUrl}/if/sso/user/me       # 获取当前用户信息地址
              token-info-uri: ${properties.sso.ssoInternal}/oauth/check_token# 验证token地址

 


1.2.3 Router的实现

词汇表主要包含以下3个组成部分:

  • Route 路由:gateway的基本构建模块。它由ID、目标URI、断言集合和过滤器集合组成。如果聚合断言结果为真,则匹配到该路由。
  • Predicate 断言:这是一个Java 8 Function Predicate。输入类型是 Spring Framework ServerWebExchange。这允许开发人员可以匹配来自HTTP请求的任何内容,例如Header或参数。
  • Filter 过滤器:这些是使用特定工厂构建的 Spring FrameworkGatewayFilter实例。所以可以在返回请求之前或之后修改请求和响应的内容。

 

Portal-Gateway路由网关

客户端向Spring Cloud Gateway发出请求。如果Gateway Handler Mapping确定请求与路由匹配,则将其发送到Gateway Web Handler。此handler通过特定于该请求的过滤器链处理请求。图中filters被虚线划分的原因是filters可以在发送代理请求之前或之后执行逻辑。先执行所有“pre filter”逻辑,然后进行请求代理。在请求代理执行完后,执行“post filter”逻辑。

 

路由规则都可以配置,具体使用可以参考一下Spring Cloud Gateway 2.1.0 中文官网文档


1.3 gateway配置和使用

由于项目使用maven模块化配置,Springboot版本为:2.1.3.RELEASE, SpringCloud版本为:Finchley.RELEASE。

gateway支持两种方式提供路由服务,其一是配置文件启用,其二则是通过代码达到目的。


1.3.1 pom配置

要在项目中引入gateway,需要引用 group  org.springframework.cloud 和 artifact id为spring-cloud-starter-gateway starter。最新的Spring Cloud Release 构建信息,请参阅Spring Cloud Project page

如果应用了该starter,但由于某种原因不希望启用网关,请进行设spring.cloud.gateway.enabled=false

重要 Spring Cloud Gateway依赖Spring Boot和Spring Webflux提供的Netty runtime。它不能在传统的Servlet容器中工作或构建为WAR

请注意:不要引入spring-boot-starter-web包,会导致Gateway启动抛出异常


1.3.2 application.yml配置实现

spring:
  cloud:
    gateway:
      routes:
      # This route rule used to forward request to activity server
      - id: activity-route
        uri: lb://activity
        predicates:
        - Path=/activity/**
        filters:
        - StripPrefix=1

注意:Gateway默认转发是全路径的,设置StripPrefix=1表示从二级url路径转发,即http://localhost:port/activity/test将会转发到http://{activity}/test


1.3.2 代码实现

@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route(r -> r.path("/activity/**")
                        .filters(f -> f.stripPrefix(1).filter(new TestGetWayFilter()).addResponseHeader("X-Response-Default-Foo", "Default-Bar"))
                        .uri("lb://activity")
                        .order(0)
                        .id("activity-route")
                )
                .build();
 }

1.4 应用案例

1.4.1 案例1-通过使用Java正则表达式灵活地重写请求路径

包含一个 regexp正则表达式参数和一个 replacement 参数. 通过使用Java正则表达式灵活地重写请求路径。

对于请求路径/foo/bar,将在发出下游请求之前将路径设置为/bar。注意,由于YAML规范,请使用 $\替换 $

cloud:
    gateway:
        routes:
             - id: service_path_route
               uri: http://222.73.213.174:10013
               predicates:
                - Path=/foo/**
               filters:
                - RewritePath=/foo/(?<segment>.*), /$\{segment}

 

该配置主要包含id、uri、predicates和fileters。

实现功能:

    1. 接口请求Potal-Gateway:http://ip:9099/foo/v1/WorkOrder/select
    2. 路径中包含foo,Potal-Gateway会对foo进行过滤,使用fileters中的规则对其进行url替换
    3. 最终由Potal-Gateway转发地址请求:http://222.73.213.174:10013/v1/WorkOrder/select

1.4.2 案例2-Cookie 路由断言 Factory

Cookie 路由断言 Factory有两个参数,cookie名称和正则表达式。请求包含次cookie名称且正则表达式为真的将会被匹配。

application.yml
spring:
  cloud:
    gateway:
      routes:
      - id: cookie_route
        uri: http://example.org
        predicates:
        - Cookie=chocolate, ch.p

 

1.4.3 案例3-Header  路由断言 Factory

 

Header 路由断言 Factory有两个参数,header名称和正则表达式。请求包含次header名称且正则表达式为真的将会被匹配。

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

 

1.4.4 案例4-路由断言 Factory

Host 路由断言 Factory包括一个参数:host name列表。使用Ant路径匹配规则,.作为分隔符。

spring:
  cloud:
    gateway:
      routes:
      - id: host_route
        uri: http://example.org
        predicates:
        - Host=**.somehost.org,**.anotherhost.org

 

1.4.5 案例5-Method 路由断言 Factory

Method 路由断言 Factory只包含一个参数: 需要匹配的HTTP请求方式

application.yml.
spring:
  cloud:
    gateway:
      routes:
      - id: method_route
        uri: http://example.org
        predicates:
        - Method=GET

所有GET请求都将被路由


 

1.4.6 案例6-Path 路由断言 Factory

Path 路由断言 Factory 有2个参数: 一个Spring PathMatcher表达式列表和可选matchOptionalTrailingSeparator标识 .

application.yml.
spring:
  cloud:
    gateway:
      routes:
      - id: host_route
        uri: http://example.org
        predicates:
        - Path=/foo/{segment},/bar/{segment}

例如: /foo/1 or /foo/bar or /bar/baz的请求都将被匹配

URI 模板变量 (如上例中的 segment ) 将以Map的方式保存于ServerWebExchange.getAttributes() key为ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE. 这些值将在GatewayFilter Factories使用以下方法来更方便地访问这些变量。

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

 

1.4.7 案例7-Query 路由断言 Factory

Query 路由断言 Factory 有2个参数: 必选项 param 和可选项 regexp.

application.yml.
spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: http://example.org
        predicates:
        - Query=baz

则包含了请求参数 baz的都将被匹配。

application.yml.
spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: http://example.org
        predicates:
        - Query=foo, ba.

 

 

如果请求参数里包含foo参数,并且值匹配为ba. 表达式,则将会被路由,如:bar and baz