首页 > 解决方案 > 在没有集中授权模块的情况下,为每个用户添加 zuul 速率限制

问题描述

我有一个正在使用的微服务架构,Spring Zuul Gateway如下图所示。 在此处输入图像描述

我的身份验证服务返回x-auth-token由 spring 身份验证解析器生成,我的令牌存储库是 redis。所以用户应该使用该服务进行身份验证,然后再使用其他服务。

我的所有其他服务都连接到同一个 redis 实例,因此当他们收到时,x-auth-token他们可以获得用户会话详细信息。我通常通过使用@PreAuthorize注释进行授权,然后指定可以访问控制器或方法的角色。

到目前为止一切正常。然后我被要求在这个架构中添加速率限制功能。因此,例如,单个用户不应向POST图书服务中的特定 api 发出超过 1 个请求。此外,如果有两个书籍服务实例,我希望在涉及速率限制时都被视为单一服务。

我发现大量文档将我推荐给这个名为spring-cloud-zuul-ratelimit 的项目。查看文档,我意识到它确实支持 redis 作为存储(对我来说很好,因为我已经有 redis)并且它还支持每个用户的处理速率限制。

问题是我的zuul网关对用户一无所知!它无权访问 redis 存储。如果我给它访问redis的权限,问题可能会解决,但另一个问题会出现:我需要授权用户两次,这需要更多的时间和更多的redis流量!一次在网关,一次在每个服务(检查角色和会话详细信息)。

我正在寻找最接近此需求列表的解决方案:

  1. 不会更改我的身份验证方法(我不能只切换到 JWT 或 OAuth)
  2. 不重复授权或 redis 查询
  3. 平衡我的服务之间的请求不应影响速率限制。如果单个用户请求服务 X 的每个实例一次,则用户发送了两个请求。
  4. 希望有一个很好的弹簧支持答案。
  5. 我希望能够动态更改限制。

标签: springspring-securityspring-cloudrate-limiting

解决方案


Zuul 网关速率限制器插件基本上根据特定密钥(可能是用户的 IP、某些 ID、请求路径或使用自定义密钥生成器的自定义组合)在时间间隔内给定用户请求来跟踪用户请求的计数器。您可以将其添加到现有的 zuul 网关应用程序中。

假设 ratelimiter-gateway 正在使用"[clientIP][userID][method][path]"存储在 redis 中的请求计数器密钥,例如"10.8.14.58:some@mail.com:POST:/books".

以下是我能想到的一些选择:

  1. 如果客户端发送一些ID,您可以直接将其用作速率限制器组合键。
  2. 如果用户只发送 JWT 令牌,您可以验证它声称获取用户 ID,假设它嵌入在令牌中,使用相同的密钥在 authn 服务中生成 JWT 令牌作为 Zuul 网关应用程序属性(使用 OS env 凭据,保险库等)。或者您可以只使用令牌作为用户 ID。
  3. 将授权逻辑移至 Spring zuul+ratelimiter 服务。它将验证对author&books服务的传入请求,从令牌中获取用户 ID。然后将其作为另一个标头(例如:“x-app-user-id”)传递给使用 SpringBoot 过滤器的上游服务。这样,上游服务不会做任何认证逻辑,它只是从 header 中读取用户 ID。author&服务之间的通信books可能使用相同的标头。当然,这是假设上游服务器不会直接从外部网络访问。

使用不同的 redis 实例作为 ratelimit 密钥存储也可能是个好主意。

至于动态配置,可以根据它的文档,通过属性调整限速配置。我不知道它是否可以在运行时通过 Spring Cloud Config 或其他远程配置实现动态调整,而无需重新启动网关应用程序。


推荐阅读