Plongée dans la façade RateLimiter de Laravel : implémentation de limitations personnalisées par utilisateur, plan ou adresse IP, jusqu’à une configuration haute disponibilité avec Redis.
La limitation de débit de Laravel repose sur la classe Illuminate\Cache\RateLimiting\Limit et la façade RateLimiter. En interne, un compteur est stocké dans un driver de cache (par défaut fichier ou Redis) pour suivre le nombre de requêtes.Le middleware throttle exécute pour chaque requête la closure définie via RateLimiter::for() ; si la limite est atteinte, il renvoie 429 Too Many Requests.
Définir des limiters personnalisés dans AppServiceProvider
La configuration de la limitation de débit se fait dans la méthode boot() de App\Providers\AppServiceProvider.
<?phpnamespace App\Providers;use Illuminate\Cache\RateLimiting\Limit;use Illuminate\Http\Request;use Illuminate\Support\Facades\RateLimiter;use Illuminate\Support\ServiceProvider;class AppServiceProvider extends ServiceProvider{ public function boot(): void { RateLimiter::for('api', function (Request $request) { return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip()); }); }}
Le premier argument de RateLimiter::for() est le nom du limiter, référencé depuis le middleware throttle. La closure passée en second argument doit renvoyer une instance de Illuminate\Cache\RateLimiting\Limit.
Fonctionnement des en-têtes de réponse (X-RateLimit-*)
Le middleware throttle ajoute automatiquement les informations de limitation aux en-têtes de la réponse.
En-tête
Description
X-RateLimit-Limit
Nombre de requêtes autorisées
X-RateLimit-Remaining
Nombre de requêtes restantes
Retry-After
Secondes avant la prochaine requête possible (uniquement lors du 429)
X-RateLimit-Reset
Timestamp UNIX auquel la limite se remet à zéro
HTTP/1.1 429 Too Many RequestsX-RateLimit-Limit: 60X-RateLimit-Remaining: 0Retry-After: 45X-RateLimit-Reset: 1717000000Content-Type: application/json{ "message": "Too Many Requests."}
// Nombre actuel de tentatives$hits = RateLimiter::attempts($key);// Secondes avant la prochaine remise à zéro$seconds = RateLimiter::availableIn($key);// Vérifier si la limite est atteinte$tooMany = RateLimiter::tooManyAttempts($key, $maxAttempts = 5);// Réinitialiser manuellement le compteur (par exemple après une déconnexion)RateLimiter::clear($key);
public function login(Request $request): mixed{ $key = 'login:' . $request->input('email'); if (RateLimiter::tooManyAttempts($key, 5)) { $seconds = RateLimiter::availableIn($key); throw ValidationException::withMessages([ 'email' => "Trop de tentatives de connexion. Réessayez dans {$seconds} secondes.", ]); } if (! Auth::attempt($request->only('email', 'password'))) { RateLimiter::hit($key, 300); // décompte pendant 5 minutes throw ValidationException::withMessages([ 'email' => 'Adresse e-mail ou mot de passe incorrect.', ]); } RateLimiter::clear($key); return redirect()->intended('/dashboard');}
Le middleware throttle est alors mappé à la classe ThrottleRequestsWithRedis, qui utilise les opérations atomiques de Redis pour un comptage précis.
Lorsque vous utilisez throttleWithRedis(), assurez-vous que Redis est disponible. Si la connexion à Redis échoue, toutes les requêtes risquent d’être refusées.