Rah*_*san 6 php throttling rate-limiting laravel laravel-5.5
我像这样使用 Laravel 的内置油门:
//File: Kernal
protected $middlewareGroups = [
'api' => ['throttle:10,3']
];
Run Code Online (Sandbox Code Playgroud)
但是,我想在我的一个控制器中执行某些操作后重置计数(例如在成功登录后)。
我可以看到这个中间件使用RateLimiter了一个名为clear.
问题是,这个怎么用?因为它依赖于keyfromThrottleRequests中间件。
object的ThrottleRequests我需要实例RateLimiterRateLimiter,我需要 的实例Cache。. .总而言之,如何使用它是无止境的..知道吗?
谢谢
由于您的问题被标记为 Laravel v5.5,因此适用于此:
您可以在控制器中使用该Illuminate\Foundation\Auth\AuthenticatesUsers特征,这样您就可以访问该clearLoginAttempts方法,该方法使用正确的密钥调用实例clear()上的方法,RateLimiter而无需提供密钥。
实际上,如果你看看它是如何实现的,你会发现一旦你的控制器使用了该特征,Illuminate\Foundation\Auth\ThrottlesLogins::clearLoginAttempts()就可以通过 检索正确的密钥。$this->throttleKey($request)AuthenticatesUsers
您始终可以Illuminate\Cache\RateLimiter使用 获取实例app(\Illuminate\Cache\RateLimiter::class),该实例又包含所有配置的限制器和缓存。问题是从这个角度来看不可能获取缓存键。因此,您确实必须首先找出密钥的设置位置和方式,以便您可以使用相同的密钥进行重置。
标准ThrottleRequests中间件在方法中设置密钥handle(),但实际的密钥取决于您的节流配置的位置和方式(例如:它是命名限制器还是仅使用数字参数设置,被调用以->by(...)显式设置密钥等.)
如果您只需要找到一个特定限制器的密钥,也许您可以在handle()方法中设置一个断点并进行检查。
在您的特定情况下,由于它不是命名限制器,因此该handle()方法将调用resolveRequestSignature以获取密钥。我认为您无法轻松地从控制器访问中间件实例。您可以做的是检查该方法如何生成密钥,并基本上复制该代码段以复制相同的密钥,但我不建议这样做,因为这是一个肮脏且脆弱的解决方案。如果您检查,您会看到密钥可以复制为如下内容:
if ($user = $request->user()) {
$key = sha1($user->getAuthIdentifier());
}
elseif ($route = $request->route()) {
$key = sha1($route->getDomain().'|'.$request->ip());
}
Run Code Online (Sandbox Code Playgroud)
但在最近的 Laravel 版本中,您可以显式设置密钥,这是更干净、更可靠的解决方案:
现在,由于问题已经相当老了,大多数人宁愿使用最新版本的 Laravel(截至 2021 年 2 月 12 日为 v8),因此对于他们来说,文档包括“分段”限制器的方法。能够根据请求(或会话数据等)为不同的请求应用单独的限制计数器。事实上,该by()方法实际上设置了key限制器。因此,您可以设置一个或多个命名限制器,例如:
RateLimiter::for('my_per_ip_limiter', function (Request $request) {
return Limit::perMinute(100)->by($request->ip());
});
Run Code Online (Sandbox Code Playgroud)
这意味着指定的限制器my_per_ip_limiter将使用 IP 作为密钥,因此您可以随时在控制器中调用:
app(\Illuminate\Cache\RateLimiter::class)->clear($request->ip());
Run Code Online (Sandbox Code Playgroud)
重置特定 IP 的限制器。或者获取到目前为止的尝试次数:
$attempts_so_far = app(\Illuminate\Cache\RateLimiter::class)->attempts($request->ip());
Run Code Online (Sandbox Code Playgroud)
事实上,您可以使用请求的任何变量(或会话或其他)来代替 IP。
然而(我认为)没有办法区分命名的限制器。因此,如果同一键也用于另一个限制器,则它们的点击将一起计数*并一起清除。my_per_ip_limiter因此,为限制器指定一个名称仅有用,以便您可以按名称将该限制器分配给特定路由,例如:
Route::post( 'login', 'Auth\LoginController@login' )
->middleware('throttle:my_per_ip_limiter');
Run Code Online (Sandbox Code Playgroud)
但是,如果您确实需要命名限制器来单独重置,则必须使用唯一的键,例如在其前面加上一些前缀,例如:
RateLimiter::for('my_other_ip_limiter', function (Request $request) {
return Limit::perMinute(100)->by('other_'.$request->ip());
});
Run Code Online (Sandbox Code Playgroud)
这可以独立于另一项来清除:
// reset my_other_ip_limiter, but not my_per_ip_limiter :
app(\Illuminate\Cache\RateLimiter::class)->clear('other_'.$request->ip());
Run Code Online (Sandbox Code Playgroud)
*:我所说的一起计数是指它们会相加,因此如果您将其中两个应用于同一个请求,则每个请求都会使计数器增加 2!