简体   繁体   中英

Spring Cloud Gateway: Set response status code in custom predicate

In the below code snippet, I am trying to match my request against a custom predicate. Upon the predicate being evaluated as false, I would like to send back a custom status code (403 Forbidden in the below snippet) instead of the default 404 that is being sent on predicate failure. Here's what I've tried.

RouteLocator

@Bean
 public RouteLocator customRoutesLocator(RouteLocatorBuilder builder 
  AuthenticationRoutePredicateFactory arpf) {
    return builder.routes()
            .route("id1", r ->r.path("/app1/**")
                .uri("lb://id1")
                .predicate(arpf.apply(new Config()))).build();
}

AuthenticationRoutePredicateFactory

public class AuthenticationRoutePredicateFactory
    extends AbstractRoutePredicateFactory<AuthenticationRoutePredicateFactory.Config> {
public AuthenticationRoutePredicateFactory() {
    super(Config.class);
}

@Override
public Predicate<ServerWebExchange> apply(Config config) {

    return (ServerWebExchange t) -> {
        try {
             Boolean isRequestAuthenticated =  checkAuthenticated();

                return isRequestAuthenticated;
            }
        } catch (HttpClientErrorException e) {
           //This status code does not carried forward and 404 is displayed instead.
            t.getResponse().setStatusCode(HttpStatus.FORBIDDEN); 
            return false;
        }

    };

}

@Validated
public static class Config {

    public Config() {
    }
}

private Boolean checkAuthenticated() {
  // Some sample logic that makes a REST call and returns TRUE/FALSE/HttpClientErrorException
 //Not shown here for simplicity.
  return true;
}

}

When the predicate returns as true, the request is forwarded to the URI. However, on false evaluation 404 is displayed, I require 403 to be displayed (On HttpClientErrorException ). Is this the right way to expect a response with custom status code?. Additionally, I also read on implementing custom webfilters for a given route that can possibly modify the response object before forwarding the request. Is there a way to invoke a filter on predicate failure in that case?

As a newbie to spring cloud gateway, I chose the wrong direction towards approaching this problem.

Clients make requests to Spring Cloud Gateway. If the Gateway Handler Mapping determines that a request matches a route, it is sent to the Gateway Web Handler. Predicates aid the Gateway Handler Mapping in determining if that request matches the route and can only return either a true or false value.

Once the request matches the route, The handler runs the request through a filter chain that is specific to the request. This is where "pre" or "post" requests can be applied before forwarding a request.

Therefore In order to send a custom response status code before conditionally forwarding the request, One must write a custom "pre" filter and this can be achieved as below. (Setting 403 status code)

AuthenticationGatewayFilterFactory

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


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

@Override
public GatewayFilter apply(Config config) {
    return (exchange, chain) -> {
        try {
            if(isRequestAuthenticated) {
                return chain.filter(exchange);
            }
            else {
                
                exchange.getResponse().setStatusCode(403); // Any status code can be set here.
                return exchange.getResponse().complete();
            }
            

        } catch (HttpClientErrorException e) {
            exchange.getResponse().setStatusCode(403); // Any status code can be set here.
            return exchange.getResponse().complete();
        }

    };
}

public static class Config {

}

private Boolean isRequestAuthenticated(String authToken) {

// Some sample logic that makes a REST call and returns TRUE/FALSE/HttpClientErrorException
 //Not shown here for simplicity.
  return true;

}

RouteLocator

 @Bean
 public RouteLocator customRoutesLocator(RouteLocatorBuilder builder 
  AuthenticationGatewayFilterFactory agff) {
    return builder.routes()
            .route("id1", r ->r.path("/app1/**")
                .uri("lb://id1")
                .filter(agff.apply(new Config()))).build();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM