3

SpringBoot中实现API速率限制的令牌桶算法项目

 6 months ago
source link: https://www.jdon.com/72862.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

SpringBoot中实现API速率限制的令牌桶算法项目

这个github项目是利用Bucket4j以及 Redis 缓存和 Spring Security 过滤器对私有 API 端点实施速率限制。

需要升级到 Spring Boot 3 和 Spring Security 6

关键组件:

流程:
在应用程序的初始启动过程中,将使用 Flyway 迁移脚本创建数据库表并填充数据。具体来说,计划表中会填充预定义的计划,每个计划都会分配一个特定的 limit_per_hour 值。

  • FREE    20
  • BUSINESS    40
  • PROFESSIONAL    100

创建用户账户时,作为请求的一部分发送的指定计划 ID 将与用户记录关联。该计划决定了适用于该用户的费率限制配置。

当用户使用认证成功后收到的有效 JWT 令牌调用私有 API 端点时,应用程序会根据用户选择的计划执行速率限制。速率限制在 RateLimitFilter 中执行,当前配置由 RateLimitingService 管理。

首次调用 API 时,RateLimitingService 会从数据源获取用户的计划详情,并将其存储在缓存中,以便在后续请求中有效检索。这些以 Bucket 形式存储的数据用于使用 Bucket4j 实现令牌 Bucket 算法。

当某个用户分配的速率限制耗尽时,将向客户端发送以下 API 响应

{
  "Status": "429 TOO_MANY_REQUESTS",
  "Description": "API request limit linked to your current plan has been exhausted."
}

可以更新当前用户计划,从而删除缓存中存储的以前的速率限制配置。更新计划的私有 API 端点已配置为使用 @BypassRateLimit 绕过费率限制检查,即使当前费率限制已用尽,也允许通过有效的 JWT 令牌进行访问。

速率限制标头
根据用户的速率限制评估传入 HTTP 请求后,RateLimitFilter 会在响应中包含额外的 HTTP 标头,以提供更多信息。这些标头有助于客户端应用程序了解速率限制状态,并相应调整其行为,以从容应对违反速率限制的情况。

绕过速率限制执行
通过使用注释来注释相应的控制器方法,可以绕过特定私有 API 端点的速率限制强制执行@BypassRateLimit。应用后,对该方法的请求不会受到RateLimitFilter.java的速率限制,并且无论用户当前的速率限制计划如何,都将被允许。

下面用于更新用户当前计划的私有 API 端点带有注释,@BypassRateLimit以确保更新到新计划的请求不受用户速率限制的限制。

@BypassRateLimit
@PutMapping(value = "/api/v1/plan")
public ResponseEntity<HttpStatus> update(@RequestBody PlanUpdationRequest planUpdationRequest) {
    planService.update(planUpdationRequest);
    return ResponseEntity.status(HttpStatus.OK).build();
}

安全过滤器
所有对私有 API 端点的请求都会被JwtAuthenticationFilter拦截。该过滤器负责验证传入访问令牌的签名并填充安全上下文。仅当访问令牌的签名成功验证后,请求才会到达RateLimitFilter,后者相应地对用户实施速率限制。

这两个自定义过滤器都添加到 Spring Security 过滤器链中并在 SecurityConfiguration 中进行配置。

任何需要公开的 API 都可以使用@PublicEndpoint进行注释。对配置的 API 路径的请求不会由任何一个过滤器进行评估,其逻辑由ApiEndpointSecurityInspector控制。

以下是声明为公共的示例控制器方法,该方法将免除身份验证检查:

@PublicEndpoint
@GetMapping(value = "/plan", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<Plan>> retrieve() {
    var response = planService.retrieve();
    return ResponseEntity.ok(response);
}

 


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK