RateLimitMiddleware.php 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. <?php
  2. namespace app\common\middleware;
  3. use think\facade\Cache;
  4. use think\Response;
  5. class RateLimitMiddleware
  6. {
  7. // 频率限制配置(单位:秒)
  8. protected $rules = [
  9. 'ip' => ['limit' => 10, 'window' => 60], // 每IP每分钟10次
  10. 'mobile' => ['limit' => 5, 'window' => 3600] // 每手机号每小时5次
  11. ];
  12. public function handle($request, \Closure $next)
  13. {
  14. $mobile = $request->param('mobile');
  15. $ip = $request->ip();
  16. // IP频率检查
  17. $ipKey = "rate:ip:{$ip}";
  18. if (!$this->checkRate($ipKey, $this->rules['ip'])) {
  19. return $this->tooManyRequests('IP请求过于频繁');
  20. }
  21. // 手机号频率检查
  22. $mobileKey = "rate:mobile:{$mobile}";
  23. if (!$this->checkRate($mobileKey, $this->rules['mobile'])) {
  24. return $this->tooManyRequests('该手机号请求过于频繁');
  25. }
  26. return $next($request);
  27. }
  28. protected function checkRate(string $key, array $rule): bool
  29. {
  30. $count = Cache::get($key, 0);
  31. if ($count >= $rule['limit']) {
  32. return false;
  33. }
  34. Cache::inc($key);
  35. if ($count === 0) {
  36. Cache::expire($key, $rule['window']);
  37. }
  38. return true;
  39. }
  40. protected function tooManyRequests(string $message): Response
  41. {
  42. return json([
  43. 'code' => 429,
  44. 'msg' => $message,
  45. 'data' => null
  46. ])->code(429);
  47. }
  48. }