18

I am trying to use a ZuulFilter in a simple spring-cloud-Netflix Api gateway (reverse proxy) in order to authenticate requests against a custom authentication provider (via Rest call).

The Filter should reject unauthorized requests with a 401 and don't pass those requests further down to the proxied services.

Is that even possible for a ZuulFilter? I did not find documentation, example or something in Zuuls api.

Any suggestions?

Thomas Jäckle
  • 799
  • 2
  • 5
  • 13

3 Answers3

26

I got this to work, took some digging. Make sure your request isn't cached already. Just call this method from your run() method inside your ZuulFilter.

/**
 * Reports an error message given a response body and code.
 * 
 * @param body
 * @param code
 */
private void setFailedRequest(String body, int code) {
    log.debug("Reporting error ({}): {}", code, body);
    RequestContext ctx = RequestContext.getCurrentContext();
    ctx.setResponseStatusCode(code);
    if (ctx.getResponseBody() == null) {
        ctx.setResponseBody(body);
        ctx.setSendZuulResponse(false);
    }
}
abeauchamp
  • 766
  • 1
  • 15
  • 28
  • 1
    This works - one simple "ctx.setSendZuulResponse(false);" was missing in our code :) – Thomas Jäckle Sep 11 '15 at 09:09
  • @thomas-jäckle, Assuming you call the auth-service from a pre filter, how do you get the body? What's the code? – Abhijit Sarkar May 28 '16 at 00:07
  • 1
    The response body will be empty because it hasn't made a call yet (pre filter). You can actually just set ctx.setSendZuulResponse(false); to accomplish what you need likely. – abeauchamp May 30 '16 at 05:46
  • Using `ctx.getResponse().sendError(code)` instead of `ctx.setResponseStatusCode(code)` and `ctx.setResponseBody(body);` allowed Spring framework to handle the error in my case. – Vijay Aggarwal Sep 01 '18 at 08:23
4

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

also see Netflix Zuul - block request routing

Community
  • 1
  • 1
Bruce
  • 1,230
  • 16
  • 13
  • 1
    doing ctx.unset() makes Zuul throw an exception. Just ctx.setSendZuulResponse(false); works for me. – icordoba Oct 08 '17 at 09:29
  • ctx.unset() used to work with SpringBoot 1.x and the relative spring-cloud-netflix dependencies – Sam May 03 '19 at 13:58
1

If you want to use authentication with the Spring Cloud then try the Spring Security Cloud project.

Tyutyutyu
  • 103
  • 4
  • Yes, that project has some useful tools for using oauth. Zuul is basically a blank slate. Spring Cloud Netflix Zuul has some simple routing and forwarding functionality. Zuul filters give you access to the raw http request and response, so you can do anything you need. See my answer to this question for getting started: http://stackoverflow.com/questions/31055736/creating-custom-zuul-filters – spencergibb Jul 08 '15 at 19:32