Spring boot 使用Zuul作为身份验证网关

Spring boot 使用Zuul作为身份验证网关,spring-boot,spring-cloud,microservices,gateway,netflix-zuul,Spring Boot,Spring Cloud,Microservices,Gateway,Netflix Zuul,背景 我想实现本文中介绍的设计 可通过下图进行总结: 客户端首先通过IDP进行身份验证(OpenID Connect/OAuth2) IDP返回一个访问令牌(没有用户信息的不透明令牌) 客户端使用授权标头中的访问令牌通过API网关进行调用 API网关使用访问令牌向IDP发出请求 IDP验证访问令牌是否有效,并以JSON格式返回用户信息 API网关将用户信息存储在JWT中,并使用私钥对其进行签名。然后将JWT传递给下游服务,后者使用公钥验证JWT 如果一个服务必须调用另一个服务来满足请求,它将传

背景

我想实现本文中介绍的设计

可通过下图进行总结:

  • 客户端首先通过IDP进行身份验证(OpenID Connect/OAuth2)
  • IDP返回一个访问令牌(没有用户信息的不透明令牌)
  • 客户端使用授权标头中的访问令牌通过API网关进行调用
  • API网关使用访问令牌向IDP发出请求
  • IDP验证访问令牌是否有效,并以JSON格式返回用户信息
  • API网关将用户信息存储在JWT中,并使用私钥对其进行签名。然后将JWT传递给下游服务,后者使用公钥验证JWT
  • 如果一个服务必须调用另一个服务来满足请求,它将传递JWT,JWT作为请求的身份验证和授权
  • 到目前为止我拥有的

    我通过以下方式完成了大部分工作:

    • Spring云作为一个全球框架
    • Spring boot启动单个服务
    • Netflix Zuul作为API网关
    我还编写了一个Zuul预过滤器,用于检查访问令牌、联系IDP并创建JWT。然后将JWT添加到转发到下游服务的请求的报头中

    问题

    现在我的问题是针对Zuul及其过滤器的。如果API网关中的身份验证因任何原因失败,我如何停止路由并直接使用401响应,而不继续过滤链和转发调用

    此时,如果身份验证失败,过滤器不会将JWT添加到报头,401将来自下游服务。我希望我的网关能阻止这个不必要的呼叫


    我试着看看如何使用
    com.netflix.zuul.context.RequestContext
    来实现这一点,但是文档很差,我找不到方法

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

    我知道我很晚才回答。 您可以使用zuul的预过滤器接近。下面给出了您必须遵循的步骤

    //1。使用pre类型创建筛选器
    //2. 将过滤器的顺序设置为大于5,因为我们需要在zuul的预分解过滤器之后运行过滤器。
    @组成部分
    公共类CustomPreZuulFilter扩展了ZuulFilter{
    私有最终记录器Logger=LoggerFactory.getLogger(this.getClass());
    @凌驾
    公共对象运行(){
    final RequestContext RequestContext=RequestContext.getCurrentContext();
    info(“在zuul过滤器中”+requestContext.getRequest().getRequestURI());
    字节[]编码;
    试一试{
    encoded=Base64.encode(“fooClientIdPassword:secret.getBytes(“UTF-8”);
    addZuulRequestHeader(“授权”、“基本”+新字符串(编码));
    final HttpServletRequest req=requestContext.getRequest();
    if(requestContext.getRequest().getHeader(“授权”)==null
    &&!req.getContextPath()包含(“登录”)){
    requestContext.unset();
    requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
    }否则{
    //下一个逻辑
    }
    }
    }捕获(最终未支持的编码异常e){
    logger.error(“预过滤器中出现错误”,e);
    }
    返回null;
    }
    @凌驾
    公共布尔值shouldFilter(){
    返回true;
    }
    @凌驾
    public int filterOrder(){
    返回6;
    }
    @凌驾
    公共字符串筛选器类型(){
    返回“pre”;
    }
    }
    

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

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

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

    为什么不使用Spring云安全性来实现这一点?这为afaik提供了开箱即用的功能。@M.Deinum我认为我没有足够的控制来实现这个特定的设计。我需要在我的安全网络外部有访问令牌,在内部有JWT。我对Spring云安全没有太多经验。你认为我可以用它来实现我的设计吗?Spring云安全只将相同的令牌转发给下游服务。它不能像@phoenix7360那样交换或增强代币。然而,它是一个合理的构建块。