简体   繁体   English

如何使用 Spring 云网关自定义过滤器过滤每个请求?

[英]How to use a Spring Cloud Gateway Custom Filter to filter every request?

It's my first time at Spring Cloud Gateway implementation.这是我第一次使用 Spring 云网关实施。

I need filter every request and apply a filter validation on some paths.我需要过滤每个请求并在某些路径上应用过滤器验证。 Following the Baeldung Custom Filters tutorial I make a simple application to filter requests.按照Baeldung 自定义过滤器教程,我制作了一个简单的应用程序来过滤请求。

The application must release paths like /actuator/health and validate specific paths to backend service.应用程序必须发布/actuator/health之类的路径,并验证后端服务的特定路径。 So far, I've implemented a GlobalFilter and a GatewayFilterFactory .到目前为止,我已经实现了GlobalFilterGatewayFilterFactory The Global filter is called every request but the GatewayFilter is called just once when application starts, that way I can't make the auth logic to every request.每个请求都会调用全局过滤器,但在应用程序启动时只调用一次 GatewayFilter,这样我就无法为每个请求创建身份验证逻辑。 The auth logic is about a specific header field. auth 逻辑是关于一个特定的 header 字段。 So, my grained questions are:所以,我的粒度问题是:

  1. How validate every request with a specific path?如何使用特定路径验证每个请求?
  2. How refuse a request and send a error message?如何拒绝请求并发送错误消息?

GlobalFilter全局过滤器

@Component
public class LoggingGlobalPreFilter implements GlobalFilter {

    final Logger LOGGER = LoggerFactory.getLogger(LoggingGlobalPreFilter.class);

    @Override
    public Mono<Void> filter(
            ServerWebExchange exchange,
            GatewayFilterChain chain) {
        LOGGER.info("Global Pre Filter executed");
        return chain.filter(exchange);
    }

}

GatewayFilter网关过滤器

@Component
public class LoggingGatewayFilterFactory extends
        AbstractGatewayFilterFactory<LoggingGatewayFilterFactory.Config> {

    final Logger LOGGER =
            LoggerFactory.getLogger(LoggingGatewayFilterFactory.class);

    public LoggingGatewayFilterFactory() {
        super(Config.class);
    }

    private Mono<Void> onError(ServerWebExchange exchange, String err, HttpStatus httpStatus)  {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(httpStatus);
        return response.setComplete();
    }

    private boolean isAuthorizationValid(String authorizationHeader) {
        boolean isValid = true;
        return authorizationHeader.equals("x-header");
    }

    @Override
    public GatewayFilter apply(Config config) {
        LOGGER.info("M=apply, Msg=Applying Gateway Filter....");
        return ((exchange, chain) -> {
            LOGGER.info("M=apply, Msg=Applying Gateway Filter...."); // APARENTELLY NEVER ENTER HERE.
            ServerHttpRequest request = exchange.getRequest();

            if (!request.getHeaders().containsKey(TsApiGatewayConstants.HEADER_APIKEY)) {
                return this.onError(exchange, TsApiGatewayConstants.MESSAGE_API_KEY_MISSING, HttpStatus.UNAUTHORIZED);
            }

            String apiKey = request.getHeaders().get(TsApiGatewayConstants.HEADER_APIKEY).get(0);
            String userAgent = request.getHeaders().get(TsApiGatewayConstants.HEADER_USER_AGENT).get(0);

            if (!this.isAuthorizationValid(userAgent)) {
                return this.onError(exchange, TsApiGatewayConstants.MESSAGE_API_KEY_INVALID, HttpStatus.UNAUTHORIZED);
            }

            return chain.filter(exchange);
        });
    }

    public static class Config {
        private String baseMessage;
        private boolean preLogger;
        private boolean postLogger;

        public Config(String baseMessage, boolean preLogger, boolean postLogger) {
            this.baseMessage = baseMessage;
            this.preLogger = preLogger;
            this.postLogger = postLogger;
        }

        public String getBaseMessage() {
            return baseMessage;
        }

        public void setBaseMessage(String baseMessage) {
            this.baseMessage = baseMessage;
        }

        public boolean isPreLogger() {
            return preLogger;
        }

        public void setPreLogger(boolean preLogger) {
            this.preLogger = preLogger;
        }

        public boolean isPostLogger() {
            return postLogger;
        }

        public void setPostLogger(boolean postLogger) {
            this.postLogger = postLogger;
        }
    }
}

application.yml应用程序.yml

  cloud:
    gateway:
      routes:
      - id: service_route
        uri: https://backend-url:443
        predicates:
          - Path=/api
        filters:
         - Logging

Example path to filter: https://backend-url:443/api/service1过滤器的示例路径: https://backend-url:443/api/service1

I've found a way to solve it.我找到了解决它的方法。 I've used a RouteConfiguration component to set the routes and a GatewayFilter class.我使用了一个 RouteConfiguration 组件来设置路由和一个 GatewayFilter class。 On the RouteConfiguration's Bean I've seted the specific filter to the route path.在 RouteConfiguration 的 Bean 上,我已将特定过滤器设置为路由路径。 On my case I've used a filter to make an authentication.就我而言,我使用过滤器进行身份验证。

GatewayFilter网关过滤器

@RefreshScope
@Component
public class AuthenticationFilter implements GatewayFilter {

    final Logger LOGGER = LoggerFactory.getLogger(AuthenticationFilter.class);

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();

// Make your business logic, this is a simple sample.


        if (!request.getHeaders().containsKey("x-api-key")) {
            return this.onError(exchange,"api-key missing",HttpStatus.FORBIDDEN);
        }

        return chain.filter(exchange); // Forward to route
    }

    private Mono<Void> onError(ServerWebExchange exchange, String err, HttpStatus httpStatus)  {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(httpStatus);
        return response.setComplete();
    }

RouteConfiguration路由配置

@RefreshScope
@Configuration
public class RouteConfiguration {

    @Value("${routes.api}")
    private String apiHost;

    @Autowired
    AuthenticationFilter authenticationFilter;

    @Bean
    public RouteLocator apiRoutes(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("CHOICE A ROUTE ID",p -> p
                        .path("/api/**")
                        .filters(f -> f
                                .filter(authenticationFilter) // You can add more filters here.
                                .stripPrefix(1))
                        .uri(apiHost))
                .build();
    }

}

if you want validate every request,you should impl the Ordered interface and and return -2;如果你想验证每个请求,你应该实现 Ordered 接口并返回 -2; eg:例如:

     @Component
public class WrapperResponseGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public int getOrder() {
        // -1 is response write filter, must be called before that
        return -2;
    }
}

refuse a request and send a error message you can see this.use MonoUtil.buildServerResponse method.拒绝请求并发送错误消息你可以看到 this.use MonoUtil.buildServerResponse 方法。

MonoUtil MonoUtil

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在 application.yml Spring Cloud Gateway 中指定自定义过滤器 - How to Specify custom filter in application.yml Spring Cloud Gateway 如何在 Spring 云网关中添加特定于路由的自定义过滤器 - How to add a custom filter specific to a route in Spring Cloud Gateway Spring Cloud Gateway 自定义过滤器工厂的单元测试 - Unit testing for Spring Cloud Gateway Custom Filter Factory Spring 云网关 - 如何修改后过滤器中的响应正文 - Spring Cloud Gateway - How To Modify Response Body In Post Filter Spring Cloud Gateway-尝试在Web过滤器中读取请求正文时请求被卡住 - Spring Cloud Gateway - request stuck when trying to read request body in web filter Spring cloud sleuth ExtraFieldPropagation在Spring cloud Gateway Filter中失败 - Spring cloud sleuth ExtraFieldPropagation fail in Spring cloud Gateway Filter Spring 网关应用程序找不到自定义过滤器 - Spring gateway application unable to find custom filter 如何使用过滤器并在 Spring 中抛出自定义异常? - How to use filter and throw a custom exception with Spring? Spring WebsecurityConfig正在为每个请求调用过滤器 - Spring WebsecurityConfig is calling filter every request 在 Spring Cloud Gateway 过滤器中提取 WebClient GET 响应值 - Extract WebClient GET response values within a Spring Cloud Gateway filter
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM