diff --git a/cookbook/security/index.rst b/cookbook/security/index.rst index c9a478c927a..3efdd455016 100644 --- a/cookbook/security/index.rst +++ b/cookbook/security/index.rst @@ -23,6 +23,7 @@ Authentication (Identifying/Logging in the User) multiple_user_providers firewall_restriction host_restriction + user_checkers Authorization (Denying Access) ------------------------------ diff --git a/cookbook/security/user_checkers.rst b/cookbook/security/user_checkers.rst new file mode 100644 index 00000000000..83ef18e63c3 --- /dev/null +++ b/cookbook/security/user_checkers.rst @@ -0,0 +1,215 @@ +.. index:: + single: Security; Creating and Enabling Custom User Checkers + +How to Create and Enable Custom User Checkers +============================================= + +During the authentication of a user, additional checks might be required to verify +if the identified user is allowed to log in. By defining a custom user checker, you +can define per firewall which checker should be used. + +.. versionadded:: 2.8 + Defining a custom user checker was introduced in Symfony 2.8. + + +Creating a Custom User Checker +------------------------------ + +User checkers are defined in PHP classes that must implement the +:class:`UserCheckerInterface Symfony\\Component\\Security\\Core\\UserCheckerInterface`. +This interface defines two methods called ``checkPreAuth()`` and ``checkPostAuth()`` +to perform checks before and after user authentication. If one or more +conditions are not met, an exception should be thrown which extends the +:class:`AccountStatusException Symfony\\Component\\Security\\Core\\Exception\\AccountStatusException` + +.. code-block:: php + + namespace App\Security; + + use Symfony\Component\Security\Core\User\UserCheckInterface; + + class UserChecker implements UserCheckerInterface + { + public function checkPreAuth(UserInterface $user) + { + if (!$user instanceof AppUser) { + return; + } + + // user is deleted, show a generic Account Not Found message. + if ($user->isDeleted()) { + throw new AccountDeletedException('...'); + } + } + + public function checkPostAuth(UserInterface $user) + { + if (!$user instanceof AppUser) { + return; + } + + // user account is expired, the user may be notified + if ($user->isExpired()) { + throw new AccountExpiredException('...'); + } + } + } + +Enabling the Custom User Checker +-------------------------------- + +All that's left to be done is creating a service definition and configuring +this in the firewall configuration. Configuring the service is done like any +other service: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/services.yml + services: + app.user_checker: + class: App\Security\UserChecker + + .. code-block:: xml + + + + + + + + + + + .. code-block:: php + + // app/config/services.php + use Symfony\Component\DependencyInjection\Definition; + + $userChecker = new Definition('App\Security\UserChecker'); + $container->setDefinition('app.user_checker', $userChecker); + +All that's left to do is add the checker to the desired firewall where the value +is the service id of your user checker: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/security.yml + + # ... + security: + firewalls: + secured_area: + pattern: ^/ + user_checker: app.user_checker + # ... + + .. code-block:: xml + + + + + + + + + app.user_checker + + + + + + .. code-block:: php + + // app/config/security.php + + // ... + $container->loadFromExtension('security', array( + 'firewalls' => array( + 'secured_area' => array( + 'pattern' => '^/', + 'user_checker' => 'app.user_checker', + // ... + ), + ), + )); + + +Additional Configurations +------------------------- + +It's possible to have a different user checker per firewall. + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/security.yml + + # ... + security: + firewalls: + admin: + pattern: ^/admin + user_checker: app.admin_user_checker + # ... + secured_area: + pattern: ^/ + user_checker: app.user_checker + + .. code-block:: xml + + + + + + + + + app.admin_user_checker + + + + app.user_checker + + + + + + .. code-block:: php + + // app/config/security.php + + // ... + $container->loadFromExtension('security', array( + 'firewalls' => array( + 'admin' => array( + 'pattern' => '^/admin', + 'user_checkers' => 'app.admin_user_checker' + // ... + ), + 'secured_area' => array( + 'pattern' => '^/', + 'user_checker' => 'app.user_checker', + // ... + ), + ), + )); + +.. note:: + + Internally the user checkers are aliased per firewall. For `secured_area` the alias + `security.user_checker.secured_area` would point to `app.user_checker`.