From 3892e26df91cd69892c9564571073a58b0a94a41 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sun, 9 Aug 2020 16:20:30 +0200 Subject: [PATCH] Clarify authentication entry point and access denied handler --- security/access_denied_handler.rst | 181 ++++++++++++++++++++++++++--- 1 file changed, 166 insertions(+), 15 deletions(-) diff --git a/security/access_denied_handler.rst b/security/access_denied_handler.rst index e9e780e75ef..eed7589bee2 100644 --- a/security/access_denied_handler.rst +++ b/security/access_denied_handler.rst @@ -1,17 +1,116 @@ .. index:: single: Security; Creating a Custom Access Denied Handler -How to Create a Custom Access Denied Handler -============================================ +How to Customize Access Denied Responses +======================================== -When your application throws an ``AccessDeniedException``, you can handle this exception -with a service to return a custom response. +In Symfony, you can throw an +:class:`Symfony\\Component\\Security\\Core\\Exception\\AccessDeniedException` +to disallow access to the user. Symfony will handle this exception and +generates a response based on the authentication state: -First, create a class that implements +* **If the user is not authenticated** (or authenticated anonymously), an + authentication entry point is used to generated a response (typically + a redirect to the login page or an *401 Unauthorized* response); +* **If the user is authenticated, but does not have the required + permissions**, a *403 Forbidden* response is generated. + +Customize the Unauthorized Response +----------------------------------- + +You need to create a class that implements +:class:`Symfony\\Component\\Security\\Http\\EntryPoint\\AuthenticationEntryPointInterface`. +This interface has one method (``start()``) that is called whenever an +unauthenticated user tries to access a protected resource:: + + // src/Security/AuthenticationEntryPoint.php + namespace App\Security; + + use Symfony\Component\HttpFoundation\RedirectResponse; + use Symfony\Component\HttpFoundation\Request; + use Symfony\Component\HttpFoundation\Session\SessionInterface; + use Symfony\Component\Security\Core\Exception\AuthenticationException; + use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; + + class AuthenticationEntryPoint implements AuthenticationEntryPointInterface + { + private $urlGenerator; + private $session; + + public function __construct(UrlGeneratorInterface $urlGenerator, SessionInterface $session) + { + $this->urlGenerator = $urlGenerator; + $this->session = $session; + } + + public function start(Request $request, AuthenticationException $authException = null): RedirectResponse + { + // add a custom flash message and redirect to the login page + $this->session->getFlashBag()->add('note', 'You have to login in order to access this page.'); + + return new RedirectResponse($this->urlGenerator->generate('security_login')); + } + } + +That's it if you're using the :ref:`default services.yaml configuration `. +Otherwise, you have to register this service in the container. + +Now, configure this service ID as the entry point for the firewall: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/security.yaml + firewalls: + # ... + + main: + # ... + entry_point: App\Security\AuthenticationEntryPoint + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // config/packages/security.php + use App\Security\AuthenticationEntryPoint; + + $container->loadFromExtension('security', [ + 'firewalls' => [ + 'main' => [ + // ... + 'entry_point' => AuthenticationEntryPoint::class, + ], + ], + ]); + +Customize the Forbidden Response +-------------------------------- + +Create a class that implements :class:`Symfony\\Component\\Security\\Http\\Authorization\\AccessDeniedHandlerInterface`. -This interface defines one method called ``handle()`` where you can implement whatever -logic that should run when access is denied for the current user (e.g. send a -mail, log a message, or generally return a custom response):: +This interface defines one method called ``handle()`` where you can +implement whatever logic that should execute when access is denied for the +current user (e.g. send a mail, log a message, or generally return a custom +response):: namespace App\Security; @@ -49,11 +148,21 @@ configure it under your firewall: .. code-block:: xml - - - App\Security\AccessDeniedHandler - - + + + + + + + + + .. code-block:: php @@ -69,5 +178,47 @@ configure it under your firewall: ], ]); -That's it! Any ``AccessDeniedException`` thrown by code under the ``main`` firewall -will now be handled by your service. +Customizing All Access Denied Responses +--------------------------------------- + +In some cases, you might want to customize both responses or do a specific +action (e.g. logging) for each ``AccessDeniedException``. In this case, +configure a :ref:`kernel.exception listener `:: + + // src/EventListener/AccessDeniedListener.php + namespace App\EventListener; + + use Symfony\Component\EventDispatcher\EventSubscriberInterface; + use Symfony\Component\HttpFoundation\Response; + use Symfony\Component\HttpKernel\Event\ExceptionEvent; + use Symfony\Component\HttpKernel\KernelEvents; + use Symfony\Component\Security\Core\Exception\AccessDeniedException; + + class AccessDeniedListener implements EventSubscriberInterface + { + public static function getSubscribedEvents(): array + { + return [ + // the priority must be greater than the Security HTTP + // ExceptionListener, to make sure it's called before + // the default exception listener + KernelEvents::EXCEPTION => ['onKernelException', 2], + ]; + } + + public function onKernelException(ExceptionEvent $event): void + { + $exception = $event->getException(); + if (!$exception instanceof AccessDeniedException) { + return; + } + + // ... perform some action (e.g. logging) + + // optionally set the custom response + $event->setResponse(new Response(null, 403)); + + // or stop propagation (prevents the next exception listeners from being called) + //$event->stopPropagation(); + } + } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy