Reputation: 1929
We are using Spring Cloud Gateway with Spring Boot 2 and reactive WebFlux module.
There is an authentication filter which is added for one of the routes. Now if we throw a RuntimeException with a particular status code, it is really not picking up.
Earlier this authentication check was part of the HandlerInterceptor in Spring, but now we cannot use the web module along with WebFlux (conflict from Spring cloud gateway).
Example:
@Override
public GatewayFilter apply(Object config) {
ServerHttpRequest httpRequest = exchange.getRequest();
if(!someUtil.validRequest(httpRequest) {
throw new RuntimeException("Throw 401 Unauthorized with Custom error code and message");
}
}
Currently, the actual response always gives a 500 internal server error. From where is this coming from? Can we get hold of the errors from Filters here?
Upvotes: 6
Views: 10642
Reputation: 375
You can implement a custom error handler, and here is the Spring Boot document.
Or you can simply throw a ResponseStatusException. The default error handler will render the specific status.
Upvotes: 2
Reputation: 11
Keep in mind, as of the time of writing, spring-cloud-gateway uses Spring Framework WebFlux. This means that the approach would be different. You can get hold of the exception in a filter as shown below.
Declare an exception like this:
public class UnauthorisedException extends ResponseStatusException {
public UnauthorisedException(HttpStatusCode status) {
super(status);
}
public UnauthorisedException(HttpStatusCode status, String reason) {
super(status, reason);
}
}
NB: The exception extends ResponseStatusException.
The ControllerAdvice class can be implemented as follows:
@ControllerAdvice
public class MyErrorWebExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(UnauthorisedException.class)
public Mono<ServerResponse> handleIllegalState(ServerWebExchange exchange, UnauthorisedException exc) {
exchange.getAttributes().putIfAbsent(ErrorAttributes.ERROR_ATTRIBUTE, exc);
return ServerResponse.from(ErrorResponse.builder(exc,HttpStatus.FORBIDDEN,exc.getMessage()).build());
}
}
In your filter you can now implement the apply
method as follows:
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
if (request.getHeaders().get("token") == null){ //test is an example
throw new UnauthorisedException(HttpStatus.FORBIDDEN, "Not Authorised from Gateway");
}
ServerHttpRequest.Builder builder = request.mutate();
return chain.filter(exchange.mutate().request(builder.build()).build());
};
}
Upvotes: -1