60]), '/login', Response::HTTP_TOO_MANY_REQUESTS ); } public function incrementAttempts(User $user, Request $request): void { $this->rateLimiter->hit($this->getUserKey($user)); $this->rateLimiter->hit($this->getRequestKey($request)); } public function decrementAttempts(User $user, Request $request): void { $this->rateLimiter->decrement($this->getUserKey($user)); $this->rateLimiter->decrement($this->getRequestKey($request)); } public function hasHitLimit(User $user, Request $request): bool { return $this->rateLimiter->tooManyAttempts($this->getUserKey($user), $this->maxUserAttemptsPerMinute + 1) || $this->rateLimiter->tooManyAttempts($this->getRequestKey($request), $this->maxIpAttemptsPerMinute + 1); } protected function getUserKey(User $user): string { return "mfa-attempt::user::{$user->id}"; } protected function getRequestKey(Request $request): string { return "mfa-attempt::request::{$request->ip()}"; } }