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);  
}

[https://www.jdon.com/72862.html](https://www.jdon.com/72862.html

  • 19
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
令牌桶算法和漏桶算法都是常用于限制流量的算法。下面分别介绍如何用Java实现这两种算法: 1. 令牌桶算法 令牌桶算法是一种基于令牌的流量控制算法,通过固定速率往桶里放入令牌,请求需要先获取令牌,只有获取到令牌才能进行处理,否则等待直到获取到令牌。 ``` public class TokenBucket { private int capacity; // 桶的容量 private int tokens; // 当前令牌数 private long lastRefillTime; // 上次添加令牌的时间 private double refillRate; // 每秒添加的令牌数 public TokenBucket(int capacity, double refillRate) { this.capacity = capacity; this.tokens = capacity; this.refillRate = refillRate; this.lastRefillTime = System.currentTimeMillis(); } public synchronized boolean tryConsume(int tokens) { refill(); // 先添加新的令牌 if (this.tokens >= tokens) { this.tokens -= tokens; return true; } return false; } private void refill() { long now = System.currentTimeMillis(); double seconds = (now - lastRefillTime) / 1000.0; int newTokens = (int) (seconds * refillRate); if (newTokens > 0) { tokens = Math.min(tokens + newTokens, capacity); lastRefillTime = now; } } } ``` 2. 漏桶算法 漏桶算法是一种基于漏桶的流量控制算法,通过一个固定容量的漏桶来控制请求处理的速率。请求先进入漏桶,然后以固定速率从漏桶流出,如果漏桶已满,则请求被拒绝。 ``` public class LeakyBucket { private int capacity; // 桶的容量 private int water; // 当前水量 private long lastLeakTime; // 上次漏水的时间 private double leakRate; // 每秒漏水的速度 public LeakyBucket(int capacity, double leakRate) { this.capacity = capacity; this.water = 0; this.leakRate = leakRate; this.lastLeakTime = System.currentTimeMillis(); } public synchronized boolean tryConsume(int water) { leak(); // 先漏水 if (this.water + water <= capacity) { this.water += water; return true; } return false; } private void leak() { long now = System.currentTimeMillis(); double seconds = (now - lastLeakTime) / 1000.0; int leakAmount = (int) (seconds * leakRate); if (leakAmount > 0) { this.water = Math.max(0, water - leakAmount); lastLeakTime = now; } } } ``` 以上是基于Java实现令牌桶算法和漏桶算法的示例代码,可以根据实际需求进行调整和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值