使用Zuul作为身份验证网关

时间:2016-05-12 07:42:05

标签: spring-boot spring-cloud microservices gateway netflix-zuul

背景

我想实现此article中提供的设计。

可以通过下图总结: Security Architecture

  1. 客户端首先使用IDP(OpenID Connect / OAuth2)进行身份验证
  2. IDP返回访问令牌(不带用户信息的不透明令牌)
  3. 客户端通过API网关拨打电话,使用授权标题
  4. 中的访问令牌
  5. API网关使用访问令牌向IDP发出请求
  6. IDP验证访问令牌是否有效并以JSON格式返回用户信息
  7. API网关将用户信息存储在JWT中,并使用私钥对其进行签名。然后将JWT传递给下游服务,该服务使用公钥
  8. 验证JWT
  9. 如果服务必须调用另一项服务来完成请求,它将通过JWT作为请求的身份验证和授权
  10. 到目前为止我有什么

    我完成了大部分工作:

    • Spring cloud作为全球框架
    • Spring启动以启动个人服务
    • Netflix Zuul作为API网关

    我还编写了一个Zuul PRE过滤器,用于检查访问令牌,联系IDP并创建JWT。然后将JWT添加到转发到下游服务的请求的标头中。

    问题

    现在我的问题非常具体针对Zuul及其过滤器。如果由于任何原因在API网关中验证失败,我怎样才能停止路由并直接用401响应而不继续过滤链并转发呼叫?

    如果验证失败,过滤器不会将JWT添加到标头中,401将来自下游服务。我希望我的网关可以阻止这种不必要的呼叫。

    我试图了解如何使用com.netflix.zuul.context.RequestContext来执行此操作,但文档很差,我找不到方法。

3 个答案:

答案 0 :(得分:9)

您可以尝试在当前上下文中设置setSendZuulResponse(false)。这不应该路由请求。您也可以从上下文中调用removeRouteHost(),这将实现相同的目标。您可以使用setResponseStatusCode设置401状态代码。

答案 1 :(得分:4)

在run方法中添加以下内容,它将解决此问题

ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);

答案 2 :(得分:0)

我知道我很晚才回答 您可以使用zuul的预过滤器进行操作。您必须遵循的步骤如下所示。

 //1. create filter with type pre
 //2. Set the order of filter to greater than 5 because we need to run our filter after preDecoration filter of zuul.
 @Component
 public class CustomPreZuulFilter extends ZuulFilter {

  private final Logger logger = LoggerFactory.getLogger(this.getClass());

@Override
public Object run() {
    final RequestContext requestContext = RequestContext.getCurrentContext();
    logger.info("in zuul filter " + requestContext.getRequest().getRequestURI());
    byte[] encoded;
    try {
        encoded = Base64.encode("fooClientIdPassword:secret".getBytes("UTF-8"));
        requestContext.addZuulRequestHeader("Authorization", "Basic " + new String(encoded));

        final HttpServletRequest req = requestContext.getRequest();
        if (requestContext.getRequest().getHeader("Authorization") == null
                && !req.getContextPath().contains("login")) {
            requestContext.unset();
            requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());

        } else {
              //next logic
            }
        }

    } catch (final UnsupportedEncodingException e) {
        logger.error("Error occured in pre filter", e);
    }

    return null;
}



@Override
public boolean shouldFilter() {
    return true;
}

@Override
public int filterOrder() {
    return 6;
}

@Override
public String filterType() {
    return "pre";
}

}

requestContext.unset()将重置当前线程活动请求的RequestContext。并且您可以提供响应状态代码。