使用 Zuul 作为认证网关
Posted
技术标签:
【中文标题】使用 Zuul 作为认证网关【英文标题】:Using Zuul as an authentication gateway 【发布时间】:2018-09-05 20:14:39 【问题描述】:背景
我想实现article 中提出的设计。
可以用下图来概括:
-
客户端首先通过 IDP 进行身份验证(OpenID Connect/OAuth2)
IDP 返回一个访问令牌(没有用户信息的不透明令牌)
客户端通过 API 网关使用 Authorization 标头中的访问令牌进行调用
API 网关使用访问令牌向 IDP 发出请求
IDP验证Access Token是否有效,返回JSON格式的用户信息
API 网关将用户信息存储在 JWT 中并使用私钥对其进行签名。然后将 JWT 传递给使用公钥验证 JWT 的下游服务
如果一个服务必须调用另一个服务来完成请求,它会传递 JWT,作为请求的身份验证和授权
我目前所拥有的
我已经完成了大部分工作:
Spring Cloud 作为一个全局框架 Spring Boot 启动单个服务 Netflix Zuul 作为 API 网关我还编写了一个 Zuul PRE 过滤器,用于检查访问令牌、联系 IDP 并创建 JWT。然后将 JWT 添加到转发到下游服务的请求的标头中。
问题
现在我的问题是针对 Zuul 及其过滤器的。如果由于任何原因在 API 网关中身份验证失败,我如何才能停止路由并直接使用 401 响应而不继续过滤器链并转发调用?
目前,如果身份验证失败,过滤器不会将 JWT 添加到标头中,并且 401 将来自下游服务。我希望我的网关可以阻止这种不必要的调用。
我试图了解如何使用 com.netflix.zuul.context.RequestContext
来执行此操作,但文档很差,我找不到方法。
【问题讨论】:
你为什么不为此使用 Spring Cloud Security?为 afaik 提供了开箱即用的功能。 @M.Deinum 我认为我没有足够的控制权来实现这个特定的设计。我需要在我的安全网络之外有访问令牌,在里面有 JWT。我对 Spring Cloud 安全性没有太多经验。你认为我可以用它来实现我的设计吗? Spring Cloud Security 仅将相同的令牌中继到下游服务。它没有像@phoenix7360 想要的那样交换或增强代币的能力。但是,它是一个合理的构建模块。 【参考方案1】:您可以尝试在当前上下文中设置setSendZuulResponse(false)
。这不应该路由请求。您也可以从上下文中调用removeRouteHost()
,这将实现相同的效果。可以使用setResponseStatusCode
设置401状态码。
【讨论】:
【参考方案2】:在你的运行方法中添加以下内容,它将解决这个问题
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
【讨论】:
【参考方案3】:我知道我回答得太晚了。 您可以使用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,您可以提供响应状态码。
【讨论】:
以上是关于使用 Zuul 作为认证网关的主要内容,如果未能解决你的问题,请参考以下文章