userSession instanceof Session && $this->userSession->getSession()->get('app_api') === true && $this->userSession->getUser() === null) { // if userId is not specified and the request is authenticated by AppAPI, we skip the rate limit return; } if ($this->userSession->isLoggedIn()) { $rateLimit = $this->readLimitFromAnnotationOrAttribute($controller, $methodName, 'UserRateThrottle', UserRateLimit::class); if ($rateLimit !== null) { $this->limiter->registerUserRequest( $rateLimitIdentifier, $rateLimit->getLimit(), $rateLimit->getPeriod(), $this->userSession->getUser() ); return; } // If not user specific rate limit is found the Anon rate limit applies! } $rateLimit = $this->readLimitFromAnnotationOrAttribute($controller, $methodName, 'AnonRateThrottle', AnonRateLimit::class); if ($rateLimit !== null) { $this->limiter->registerAnonRequest( $rateLimitIdentifier, $rateLimit->getLimit(), $rateLimit->getPeriod(), $this->request->getRemoteAddress() ); } } /** * @template T of ARateLimit * * @param Controller $controller * @param string $methodName * @param string $annotationName * @param class-string $attributeClass * @return ?ARateLimit */ protected function readLimitFromAnnotationOrAttribute(Controller $controller, string $methodName, string $annotationName, string $attributeClass): ?ARateLimit { $annotationLimit = $this->reflector->getAnnotationParameter($annotationName, 'limit'); $annotationPeriod = $this->reflector->getAnnotationParameter($annotationName, 'period'); if ($annotationLimit !== '' && $annotationPeriod !== '') { return new $attributeClass( (int)$annotationLimit, (int)$annotationPeriod, ); } $reflectionMethod = new ReflectionMethod($controller, $methodName); $attributes = $reflectionMethod->getAttributes($attributeClass); $attribute = current($attributes); if ($attribute !== false) { return $attribute->newInstance(); } return null; } /** * {@inheritDoc} */ public function afterException(Controller $controller, string $methodName, \Exception $exception): Response { if ($exception instanceof RateLimitExceededException) { if (stripos($this->request->getHeader('Accept'), 'html') === false) { $response = new DataResponse([], $exception->getCode()); } else { $response = new TemplateResponse( 'core', '429', [], TemplateResponse::RENDER_AS_GUEST ); $response->setStatus($exception->getCode()); } return $response; } throw $exception; } }