Spring Cloud Gateway 将 bean 传递给自定义过滤器

Spring Cloud Gateway pass bean to custom filter

我们正在尝试使用 Spring 云网关来设置基于微服务的架构。目前,我们已经以编程方式定义了一条路线:

@ServletComponentScan
@SpringBootApplication
public class GatewayApplication {
    // to be passed to and used by custom filter
    @Autowired
    RestTemplate restTemplate;

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

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
        .route("status", r -> r
            .method(HttpMethod.GET)
            .and()
            .path("/status")
            .filters(f -> f.rewritePath("/status", "/v2/status")
                           .filter(new AuthorizationFilter(restTemplate).apply(new Config(""))))
            .uri("http://localhost:8081/"))
        .build();
    }
}

以上将通过 GET 将传入请求 /status 路由到另一个端点。我们想应用一个自定义过滤器,我们已经在 AuthorizationFilter 中实现了它。顾名思义,此过滤器是另一个微服务,它将根据凭据和权限允许或拒绝传入请求。

目前,我们正在遵循的有效模式是将 Spring RestTemplate 注入上面的网关 class,然后传递此 RestTemplate到过滤器的构造函数。

但是,如果我们想切换到使用 YAML 文件来定义所有路由,该怎么做呢?大概在这两种情况下 Spring 都会为每个传入请求构建一个新的过滤器。但是在 YAML 的情况下,我们如何在构造函数中传递一些东西?如果无法做到这一点,是否有任何其他方法可以将 RestTemplate 或任何其他资源注入自定义 Spring 网关过滤器?

您可以register your own custom GatewayFilterFactory. This allows you to provide a custom configuration, and within that configuration, you can use SpEL引用一个bean。

例如:

@Component
public class AuthenticationGatewayFilterFactory extends AbstractGatewayFilterFactory<AuthenticationGatewayFilterFactory.Config> {
    public AuthenticationGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        // TODO: Implement
    }

    public static class Config {
        private RestTemplate restTemplate;

        // TODO: Getters + Setters
    }
}

现在您可以使用 SpEL 正确引用 RestTemplate bean:

spring:
  cloud:
    gateway:
      routes:
        - id: status
          uri: http://localhost:8081/
          filters:
            - name: Authentication
              args:
                restTemplate: "#{@nameOfRestTemplateBean}"
          predicates:
            - Path=/status

或者,您可以在网关过滤器中注入一个 RestTemplate bean。例如:

@Component
public class AuthenticationGatewayFilterFactory extends AbstractGatewayFilterFactory<AuthenticationGatewayFilterFactory.Config> {
    private RestTemplate restTemplate;

    public AuthenticationGatewayFilterFactory(RestTemplate restTemplate) {
        super(Config.class);
        this.restTemplate = restTemplate;
    }

    @Override
    public GatewayFilter apply(Config config) {
        // TODO: Implement
    }

    public static class Config {
        // TODO: Implement
    }
}

注入所需的 code/configuration 不那么复杂,但如果您决定将 AuthenticationGatewayFilterFactory 放在单独的库中,它也会变得更加困难,因为 "consumers"这个库的将无法控制正在注入的RestTemplate