Skip to content

[Security] Add docs covering the ChainUserChecker #17274

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 17, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 145 additions & 0 deletions security/user_checkers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,148 @@ is the service id of your user checker:
// ...
;
};

Using Multiple User Checkers
----------------------------

.. versionadded:: 6.2

The ``ChainUserChecker`` class was added in Symfony 6.2.

It is common for applications to have multiple authentication entry points (such as
traditional form based login and an API) which may have unique checker rules for each
entry point as well as common rules for all entry points. To allow using multiple user
checkers on a firewall, a service for the :class:`Symfony\\Component\\Security\\Core\\User\\ChainUserChecker`
class is created for each firewall.

To use the chain user checker, first you will need to tag your user checker services with the
``security.user_checker.<firewall>`` tag (where ``<firewall>`` is the name of the firewall
in your security configuration). The service tag also supports the priority attribute, allowing you to define the
order in which user checkers are called::

.. configuration-block::

.. code-block:: yaml

# config/services.yaml

# ...
services:
App\Security\AccountEnabledUserChecker:
tags:
- { name: security.user_checker.api, priority: 10 }
- { name: security.user_checker.main, priority: 10 }

App\Security\APIAccessAllowedUserChecker:
tags:
- { name: security.user_checker.api, priority: 5 }

.. code-block:: xml

<!-- config/services.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services
https://symfony.com/schema/dic/services/services-1.0.xsd">

<services>
<!-- ... -->

<service id="App\Security\AccountEnabledUserChecker">
<tag name="security.user_checker.api" priority="10"/>
<tag name="security.user_checker.main" priority="10"/>
</service>

<service id="App\Security\APIAccessAllowedUserChecker">
<tag name="security.user_checker.api" priority="5"/>
</service>
</services>
</container>

.. code-block:: php

// config/services.php
namespace Symfony\Component\DependencyInjection\Loader\Configurator;

use App\Security\AccountEnabledUserChecker;
use App\Security\APIAccessAllowedUserChecker;

return function(ContainerConfigurator $configurator) {
$services = $configurator->services();

$services->set(AccountEnabledUserChecker::class)
->tag('security.user_checker.api', ['priority' => 10])
->tag('security.user_checker.main', ['priority' => 10]);

$services->set(APIAccessAllowedUserChecker::class)
->tag('security.user_checker.api', ['priority' => 5]);
};

Once your checker services are tagged, next you will need configure your firewalls to use the
``security.user_checker.chain.<firewall>`` service::

.. configuration-block::

.. code-block:: yaml

# config/packages/security.yaml

# ...
security:
firewalls:
api:
pattern: ^/api
user_checker: security.user_checker.chain.api
# ...
main:
pattern: ^/
user_checker: security.user_checker.chain.main
# ...

.. code-block:: xml

<!-- config/packages/security.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<srv:container xmlns="http://symfony.com/schema/dic/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:srv="http://symfony.com/schema/dic/services"
xsi:schemaLocation="http://symfony.com/schema/dic/services
https://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/security
https://symfony.com/schema/dic/security/security-1.0.xsd">

<config>
<!-- ... -->
<firewall name="api"
pattern="^/api"
user-checker="security.user_checker.chain.api">
<!-- ... -->
</firewall>
<firewall name="main"
pattern="^/"
user-checker="security.user_checker.chain.main">
<!-- ... -->
</firewall>
</config>
</srv:container>

.. code-block:: php

// config/packages/security.php
use Symfony\Config\SecurityConfig;

return static function (SecurityConfig $security) {
// ...
$security->firewall('api')
->pattern('^/api')
->userChecker('security.user_checker.chain.api')
// ...
;

$security->firewall('main')
->pattern('^/')
->userChecker('security.user_checker.chain.main')
// ...
;
};