Skip to content

Commit 35349c1

Browse files
committed
[RateLimiter] compound rate limiter
1 parent 11b2569 commit 35349c1

File tree

1 file changed

+117
-0
lines changed

1 file changed

+117
-0
lines changed

rate_limiter.rst

+117
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,123 @@ at all):
541541
lock factory (``lock.factory``) failed if the Symfony Lock component was not
542542
installed in the application.
543543

544+
Compound Rate Limiter
545+
---------------------
546+
547+
.. versionadded:: 7.3
548+
549+
Configuring compound rate limiters was added in 7.3.
550+
551+
You can configure multiple rate limiters to work together:
552+
553+
.. configuration-block::
554+
555+
.. code-block:: yaml
556+
557+
# config/packages/rate_limiter.yaml
558+
framework:
559+
rate_limiter:
560+
two_per_minute:
561+
policy: 'fixed_window'
562+
limit: 2
563+
interval: '1 minute'
564+
five_per_hour:
565+
policy: 'fixed_window'
566+
limit: 5
567+
interval: '1 hour'
568+
contact_form:
569+
policy: 'compound'
570+
limiters: [two_per_minute, five_per_hour]
571+
572+
.. code-block:: xml
573+
574+
<!-- config/packages/rate_limiter.xml -->
575+
<?xml version="1.0" encoding="UTF-8" ?>
576+
<container xmlns="http://symfony.com/schema/dic/services"
577+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
578+
xmlns:framework="http://symfony.com/schema/dic/symfony"
579+
xsi:schemaLocation="http://symfony.com/schema/dic/services
580+
https://symfony.com/schema/dic/services/services-1.0.xsd
581+
http://symfony.com/schema/dic/symfony
582+
https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
583+
584+
<framework:config>
585+
<framework:rate-limiter>
586+
<framework:limiter name="two_per_minute"
587+
policy="fixed_window"
588+
limit="2"
589+
interval="1 minute"
590+
/>
591+
592+
<framework:limiter name="five_per_hour"
593+
policy="fixed_window"
594+
limit="5"
595+
interval="1 hour"
596+
/>
597+
598+
<framework:limiter name="contact_form"
599+
policy="compound"
600+
>
601+
<limiter>two_per_minute</limiter>
602+
<limiter>five_per_hour</limiter>
603+
</framework:limiter>
604+
</framework:rate-limiter>
605+
</framework:config>
606+
</container>
607+
608+
.. code-block:: php
609+
610+
// config/packages/rate_limiter.php
611+
use Symfony\Config\FrameworkConfig;
612+
613+
return static function (FrameworkConfig $framework): void {
614+
$framework->rateLimiter()
615+
->limiter('two_per_minute')
616+
->policy('fixed_window')
617+
->limit(2)
618+
->interval('1 minute')
619+
;
620+
621+
$framework->rateLimiter()
622+
->limiter('two_per_minute')
623+
->policy('fixed_window')
624+
->limit(5)
625+
->interval('1 hour')
626+
;
627+
628+
$framework->rateLimiter()
629+
->limiter('contact_form')
630+
->policy('compound')
631+
->limiters(['two_per_minute', 'five_per_hour'])
632+
;
633+
};
634+
635+
Then, inject and use as normal::
636+
637+
// src/Controller/ContactController.php
638+
namespace App\Controller;
639+
640+
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
641+
use Symfony\Component\HttpFoundation\Request;
642+
use Symfony\Component\HttpFoundation\Response;
643+
use Symfony\Component\RateLimiter\RateLimiterFactory;
644+
645+
class ContactController extends AbstractController
646+
{
647+
public function registerUser(Request $request, RateLimiterFactoryInterface $contactFormLimiter): Response
648+
{
649+
$limiter = $contactFormLimiter->create($request->getClientIp());
650+
651+
if (false === $limiter->consume(1)->isAccepted()) {
652+
// either of the two limiters has been reached
653+
}
654+
655+
// ...
656+
}
657+
658+
// ...
659+
}
660+
544661
.. _`DoS attacks`: https://cheatsheetseries.owasp.org/cheatsheets/Denial_of_Service_Cheat_Sheet.html
545662
.. _`Apache mod_ratelimit`: https://httpd.apache.org/docs/current/mod/mod_ratelimit.html
546663
.. _`NGINX rate limiting`: https://www.nginx.com/blog/rate-limiting-nginx/

0 commit comments

Comments
 (0)