mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Updates for rate limiter
This commit is contained in:
parent
1856b44f01
commit
336e3f4bf0
125
app/Http/Middleware/ThrottleRequestsWithPredis.php
Normal file
125
app/Http/Middleware/ThrottleRequestsWithPredis.php
Normal file
@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Cache\RateLimiter;
|
||||
use Illuminate\Redis\Limiters\DurationLimiter;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
|
||||
class ThrottleRequestsWithPredis extends ThrottleRequests
|
||||
{
|
||||
/**
|
||||
* The Redis factory implementation.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Redis\Factory
|
||||
*/
|
||||
protected $redis;
|
||||
|
||||
/**
|
||||
* The timestamp of the end of the current duration by key.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $decaysAt = [];
|
||||
|
||||
/**
|
||||
* The number of remaining slots by key.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $remaining = [];
|
||||
|
||||
/**
|
||||
* Create a new request throttler.
|
||||
*
|
||||
* @param \Illuminate\Cache\RateLimiter $limiter
|
||||
* @param \Illuminate\Contracts\Redis\Factory $redis
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(RateLimiter $limiter)
|
||||
{
|
||||
parent::__construct($limiter);
|
||||
|
||||
$this->redis = \Illuminate\Support\Facades\Redis::connection('sentinel-cache');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param array $limits
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*
|
||||
* @throws \Illuminate\Http\Exceptions\ThrottleRequestsException
|
||||
*/
|
||||
protected function handleRequest($request, Closure $next, array $limits)
|
||||
{
|
||||
foreach ($limits as $limit) {
|
||||
if ($this->tooManyAttempts($limit->key, $limit->maxAttempts, $limit->decayMinutes)) {
|
||||
throw $this->buildException($request, $limit->key, $limit->maxAttempts, $limit->responseCallback);
|
||||
}
|
||||
}
|
||||
|
||||
$response = $next($request);
|
||||
|
||||
foreach ($limits as $limit) {
|
||||
$response = $this->addHeaders(
|
||||
$response,
|
||||
$limit->maxAttempts,
|
||||
$this->calculateRemainingAttempts($limit->key, $limit->maxAttempts)
|
||||
);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given key has been "accessed" too many times.
|
||||
*
|
||||
* @param string $key
|
||||
* @param int $maxAttempts
|
||||
* @param int $decayMinutes
|
||||
* @return mixed
|
||||
*/
|
||||
protected function tooManyAttempts($key, $maxAttempts, $decayMinutes)
|
||||
{
|
||||
$limiter = new DurationLimiter(
|
||||
$this->redis,
|
||||
$key,
|
||||
$maxAttempts,
|
||||
$decayMinutes * 60
|
||||
);
|
||||
|
||||
return tap(! $limiter->acquire(), function () use ($key, $limiter) {
|
||||
[$this->decaysAt[$key], $this->remaining[$key]] = [
|
||||
$limiter->decaysAt, $limiter->remaining,
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the number of remaining attempts.
|
||||
*
|
||||
* @param string $key
|
||||
* @param int $maxAttempts
|
||||
* @param int|null $retryAfter
|
||||
* @return int
|
||||
*/
|
||||
protected function calculateRemainingAttempts($key, $maxAttempts, $retryAfter = null)
|
||||
{
|
||||
return is_null($retryAfter) ? $this->remaining[$key] : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of seconds until the lock is released.
|
||||
*
|
||||
* @param string $key
|
||||
* @return int
|
||||
*/
|
||||
protected function getTimeUntilNextRetry($key)
|
||||
{
|
||||
return $this->decaysAt[$key] - $this->currentTime();
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@ use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Cache\RateLimiting\Limit;
|
||||
use Illuminate\Support\Facades\RateLimiter;
|
||||
use App\Http\Middleware\ThrottleRequestsWithPredis;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequestsWithRedis;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundException;
|
||||
@ -38,7 +39,7 @@ class RouteServiceProvider extends ServiceProvider
|
||||
|
||||
|
||||
if (Ninja::isHosted()) {
|
||||
app('router')->aliasMiddleware('throttle', ThrottleRequestsWithRedis::class);
|
||||
app('router')->aliasMiddleware('throttle', ThrottleRequestsWithPredis::class);
|
||||
// app('router')->aliasMiddleware('throttle', ThrottleRequests::class);
|
||||
|
||||
} else {
|
||||
|
Loading…
x
Reference in New Issue
Block a user