Laravel无认证开放API限流:同IP网络设备冲突解决方法
无认证开放API的Laravel限流替代方案(解决共享IP问题)
针对无认证开放API遇到的同一网络共享IP导致的限流误判问题,以下是几种可落地的替代方案:
1. Cookie会话标识限流
给首次访问的客户端分配唯一Cookie标识,以此作为限流依据。同一网络下不同设备的Cookie相互独立,能有效区分请求来源。
实现示例
<?php namespace App\Http\Middleware; use Closure; use Illuminate\Support\Str; use Illuminate\Http\Request; class ApiRateLimit { public function handle(Request $request, Closure $next) { // 获取或生成会话标识 $sessionId = $request->cookie('api_session_id'); if (!$sessionId) { $sessionId = Str::uuid()->toString(); $response = $next($request); // 设置有效期1天的Cookie return $response->cookie('api_session_id', $sessionId, 1440); } // Redis限流逻辑 $redis = app('redis')->connection(); $limitKey = "rate_limit:api:{$sessionId}"; $maxAttempts = 100; // 1分钟内最多100次请求 $decaySeconds = 60; $currentAttempts = $redis->incr($limitKey); if ($currentAttempts > $maxAttempts) { // 首次超限设置过期时间 if ($redis->ttl($limitKey) === -1) { $redis->expire($limitKey, $decaySeconds); } return response()->json(['message' => '请求过于频繁,请稍后再试'], 429); } // 首次请求设置过期时间 if ($currentAttempts === 1) { $redis->expire($limitKey, $decaySeconds); } return $next($request); } }
注意事项
- 需处理客户端禁用Cookie的情况,可降级为IP限流,或提示用户启用Cookie。
- Cookie标识存在被伪造的可能,若API安全性要求高,可结合IP做双重验证。
2. 自定义请求头设备标识限流
如果API面向可控客户端(如自研APP),可要求客户端在请求头中携带设备唯一标识(如IMEI、设备UUID),以此作为限流键。
实现示例
<?php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; class ApiRateLimit { public function handle(Request $request, Closure $next) { $deviceId = $request->header('X-Device-ID'); if (!$deviceId) { return response()->json(['message' => '缺少必要的设备标识'], 400); } $redis = app('redis')->connection(); $limitKey = "rate_limit:api:{$deviceId}"; $maxAttempts = 100; $decaySeconds = 60; $currentAttempts = $redis->incr($limitKey); if ($currentAttempts > $maxAttempts) { if ($redis->ttl($limitKey) === -1) { $redis->expire($limitKey, $decaySeconds); } return response()->json(['message' => '请求过于频繁,请稍后再试'], 429); } if ($currentAttempts === 1) { $redis->expire($limitKey, $decaySeconds); } return $next($request); } }
注意事项
- 第三方不可控客户端可能伪造设备ID,可结合IP+设备ID组合作为限流键,提升安全性。
3. IP+User-Agent组合限流
将客户端IP与User-Agent信息组合后哈希,作为限流标识。同一网络下不同设备的User-Agent通常存在差异,能在不增加用户操作成本的前提下提升限流精准度。
实现示例
<?php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; class ApiRateLimit { public function handle(Request $request, Closure $next) { $ip = $request->ip(); $userAgent = $request->header('User-Agent') ?? ''; // 哈希组合值避免过长 $identifier = md5($ip . $userAgent); $redis = app('redis')->connection(); $limitKey = "rate_limit:api:{$identifier}"; $maxAttempts = 100; $decaySeconds = 60; $currentAttempts = $redis->incr($limitKey); if ($currentAttempts > $maxAttempts) { if ($redis->ttl($limitKey) === -1) { $redis->expire($limitKey, $decaySeconds); } return response()->json(['message' => '请求过于频繁,请稍后再试'], 429); } if ($currentAttempts === 1) { $redis->expire($limitKey, $decaySeconds); } return $next($request); } }
注意事项
- 若同一网络下设备使用完全相同的客户端(如同一版本的浏览器),仍可能出现限流冲突,但比单纯IP限流的情况好很多。
4. 验证码驱动的临时令牌限流
对于高频请求的核心接口,可要求用户先完成验证码验证(图形/短信),验证通过后生成临时令牌,后续请求用该令牌做限流标识。这种方式能彻底区分真实用户,但会增加用户操作成本。
核心逻辑
- 首次请求接口时,返回验证码要求;
- 用户提交验证码验证通过后,生成唯一令牌并存入Redis,设置有效期(如1小时);
- 后续请求携带令牌,以令牌为标识执行限流;
- 令牌过期后,重新要求用户验证。
内容的提问来源于stack exchange,提问作者adithyan.cs
相关产品推荐
相关产品推荐

