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).

Rohi
  • 375
  • 5
  • 19

3 Answers3

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.

Kent Munthe Caspersen
  • 3,810
  • 27
  • 26
  • 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? – Dojo Sep 25 '19 at 08:41
  • 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 https://www.programcreek.com/java-api-examples/index.php?api=com.netflix.zuul.exception.ZuulException can be of use. – Kent Munthe Caspersen Sep 25 '19 at 20:36
  • 1
    @Dojo 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. – Kent Munthe Caspersen Sep 25 '19 at 20:48
  • 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. – Dojo Sep 26 '19 at 03:40
5

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

Bruce
  • 1,230
  • 16
  • 13
2

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.

Rohi
  • 375
  • 5
  • 19
  • 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. – Dojo Sep 25 '19 at 09:05