首页 文章

使用Zuul作为身份验证网关

提问于
浏览
20

Background

我想实现article中提出的设计 .

它可以通过下图总结:
Security Architecture

  • 客户端首先使用IDP进行身份验证(OpenID Connect / OAuth2)

  • IDP返回访问令牌(不带用户信息的不透明令牌)

  • 客户端通过API网关进行调用,使用Authorization标头中的访问令牌

  • API网关使用访问令牌向IDP发出请求

  • IDP验证访问令牌是否有效并以JSON格式返回用户信息

  • API网关将用户信息存储在JWT中,并使用私钥对其进行签名 . 然后将JWT传递给下游服务,该服务使用公钥验证JWT

  • 如果服务必须调用另一个服务来完成请求,它将通过JWT作为请求的身份验证和授权

What I have so far

我完成了大部分工作:

  • Spring Cloud 作为全球框架

  • Spring启动以启动个别服务

  • Netflix Zuul作为API网关

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

Problem

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

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

我试着看看如何使用 com.netflix.zuul.context.RequestContext 这样做,但文档很差,我找不到办法 .

3 回答

  • 0

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

  • 9

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

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

    我知道我很晚才回答你可以接近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 . 并且您可以提供响应状态代码 .

相关问题