Як налаштувати користувацькі відповіді відмови у доступі
Дата оновлення перекладу 2023-09-26
Як налаштувати користувацькі відповіді відмови у доступі
У Symfony, ви можете викликати AccessDeniedException, щоб заборонити доступ користувачу. Symfony обробить це виключення і згенерує відповідь, засновану на стані атунетифікації:
- Якщо користувач не аутентифікований (або аутентифікований анонімно), точка входу аутентифікації використовується для генерування відповіді (зазвичай, перенаправлення на сторінку входу у систему або відповіді 401 Неавторизовано);
- Якщо користувач аутентифікований, але не має необхідних дозволів, генерується відповідь 403 Заборонено.
Налаштуйте відповідь відмови в авторизації
Вам потрібно створити клас, що реалізує
AuthenticationEntryPointInterface.
Цей інтерфейс має один метод (start()
), який викликається, коли неаутентифікований
користувач намагається отримати доступ до захищеного джерела:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
// src/Security/AuthenticationEntryPoint.php
namespace App\Security;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
class AuthenticationEntryPoint implements AuthenticationEntryPointInterface
{
public function __construct(
private UrlGeneratorInterface $urlGenerator,
) {
}
public function start(Request $request, AuthenticationException $authException = null): RedirectResponse
{
// додайте користувацьке флеш-повідомлення та перенаправте на сторінку входу у систему
$request->getSession()->getFlashBag()->add('note', 'You have to login in order to access this page.');
return new RedirectResponse($this->urlGenerator->generate('security_login'));
}
}
Це все, якщо ви використовуєте конфігурацію services.yaml за замовчуванням . В іншому випадку, вам потрібно зареєструвати цей сервіс у контейнері.
Тепер, сконфігуруйте цей ID сервісу в якості точки входу у брандмауері:
1 2 3 4 5 6 7
# config/packages/security.yaml
firewalls:
# ...
main:
# ...
entry_point: App\Security\AuthenticationEntryPoint
Налаштуйте відповідь "заборонено"
Створіть клас, що реалізує
AccessDeniedHandlerInterface.
Цей інтерфейс визначає один метод під назвою handle()
, де ви можете реалізувати
будь-яку необхідну логіку, коли поточному користувачу відмовлено у доступі (наприклад,
надіслати листа, зробити запис логу повідомлення або просто повернути користувацьку
відповідь):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
// src/Security/AccessDeniedHandler.php
namespace App\Security;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Http\Authorization\AccessDeniedHandlerInterface;
class AccessDeniedHandler implements AccessDeniedHandlerInterface
{
public function handle(Request $request, AccessDeniedException $accessDeniedException): ?Response
{
// ...
return new Response($content, 403);
}
}
Якщо ви використовуєте конфігурацію services.yaml за замовчуванням , ви закінчили! Symfony автоматично дізнається про ваш сервіс. Потім, ви зможете сконфігурувати його під своїм брандмауером:
1 2 3 4 5 6 7
# config/packages/security.yaml
firewalls:
# ...
main:
# ...
access_denied_handler: App\Security\AccessDeniedHandler
Налаштування всіх відповідей відмови у доступі
У деяких випадках вам може захотітися і налаштувати відповіді, і виконати якусь дію
(наприклад, вхід у систему) для кожного AccessDeniedException
. У такому випадку,
сконфігуруйте слухач kernel.exception :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
// 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 [
// пріоритет має бути більше, ніж у HTTP Security
// ExceptionListener, щоб він викликався до слухача
// виключень за замовчуванням
KernelEvents::EXCEPTION => ['onKernelException', 2],
];
}
public function onKernelException(ExceptionEvent $event): void
{
$exception = $event->getThrowable();
if (!$exception instanceof AccessDeniedException) {
return;
}
// ... виконати якусь дію (наприклад, запис логів)
// за бажанням, встановити користувацьку відповідь
$event->setResponse(new Response(null, 403));
// або припинити розповсюдження (запобігає виклику наступних слухачів виключень)
//$event->stopPropagation();
}
}