Netflix Zuul - block request routing
Asked Answered
F

3

5

With Zuul I can easily define custom filters that are activated before or after the request is forwarded to the specific service.

Is there a way to block requests from being forwarded at a "pre" filter level, and send immediately the response to the client? I know something similar is doable with "static" filters, but I need to decide per request (based on the presence of certain parameters/headers in the request itself).

Flavory answered 15/5, 2016 at 20:31 Comment(0)
P
10

Here is an example of how I use zuul-filter to check for an API-key being authorized. If not, I send a 401 response to the client.

 @Override
    public Object run() {

        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();

        String apiKey = request.getHeader("X-API-KEY");
        if (!isAuthorized(apiKey)){
            // blocks the request
            ctx.setSendZuulResponse(false);

            // response to client
            ctx.setResponseBody("API key not authorized");
            ctx.getResponse().setHeader("Content-Type", "text/plain;charset=UTF-8");
            ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
        }

        return null;
    }

Note that if the client's API key is not authorized, all other filters will still be run, but the request will still fail due to ctx.setSendZuulResponse(false). When failing a response, it will by default be empty - that is, there is no headers such as Content-Type etc. It is a good idea to set them yourself so a client's browser etc. knows how to parse the response body.

Peruzzi answered 29/1, 2018 at 11:4 Comment(4)
It feels a little inefficient to execute more filters after you have determined that the request is not authorized. Is there another way to gracefully abort further execution and simply return the error code and maybe also a error message in the response body?Azurite
Will it work to throw an exception in a filter, e.g. ZuulException or ZuulRuntimeException, and then catch the exception in a SendErrorFilter (a filter with filterType "error")? Maybe some of the code examples from programcreek.com/java-api-examples/… can be of use.Peruzzi
@Azurite you probably have considered it already, but just want to point out that for all subsequent filters you can make the shouldFilter() method return false, e.g. by checking if sendZuulResponse has been falsified already - I guess you are aiming for a way to not even consider more filters and immediate return a response to the client though.Peruzzi
Yes I was looking for a way to immediately "abort" any further evaluation of filters and return a response. The shouldFilter() method sounds good. I completely missed looking at it that way.Azurite
L
7

I use a pre filter to check the authentication of the request, and if the request dose not authorized, then I return 401 and do not call the back end service any more. I do it in run() function like this:

    RequestContext ctx = getCurrentContext();
    // do something to check the authentication
    if(auth failed){
      ctx.unset();
      ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
    }

ctx.unset() tell the context to stop this request, and ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value()); set the http code to 401

Langton answered 4/5, 2017 at 1:51 Comment(0)
F
3

I found the solution, just needed to add context.setSendZuulResponse(false); in the run() method of my "pre" custom filter.

Other filters will still be called, but request won't be routed to destination.

Flavory answered 16/5, 2016 at 9:21 Comment(1)
Is there a way to avoid further filter execution? This feels a bit inefficient. Also context.setSendZuulResponse(false) is not respected if other filters call context.setResponseBody; you would then still get a response.Azurite

© 2022 - 2024 — McMap. All rights reserved.