Firewall.php 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Security\Http;
  11. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  12. use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
  13. use Symfony\Component\HttpKernel\Event\RequestEvent;
  14. use Symfony\Component\HttpKernel\KernelEvents;
  15. use Symfony\Component\Security\Http\Firewall\FirewallListenerInterface;
  16. use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
  17. /**
  18. * Firewall uses a FirewallMap to register security listeners for the given
  19. * request.
  20. *
  21. * It allows for different security strategies within the same application
  22. * (a Basic authentication for the /api, and a web based authentication for
  23. * everything else for instance).
  24. *
  25. * @author Fabien Potencier <fabien@symfony.com>
  26. */
  27. class Firewall implements EventSubscriberInterface
  28. {
  29. private $map;
  30. private $dispatcher;
  31. private $exceptionListeners;
  32. public function __construct(FirewallMapInterface $map, EventDispatcherInterface $dispatcher)
  33. {
  34. $this->map = $map;
  35. $this->dispatcher = $dispatcher;
  36. $this->exceptionListeners = new \SplObjectStorage();
  37. }
  38. public function onKernelRequest(RequestEvent $event)
  39. {
  40. if (!$event->isMasterRequest()) {
  41. return;
  42. }
  43. // register listeners for this firewall
  44. $listeners = $this->map->getListeners($event->getRequest());
  45. $authenticationListeners = $listeners[0];
  46. $exceptionListener = $listeners[1];
  47. $logoutListener = $listeners[2];
  48. if (null !== $exceptionListener) {
  49. $this->exceptionListeners[$event->getRequest()] = $exceptionListener;
  50. $exceptionListener->register($this->dispatcher);
  51. }
  52. // Authentication listeners are pre-sorted by SortFirewallListenersPass
  53. $authenticationListeners = function () use ($authenticationListeners, $logoutListener) {
  54. if (null !== $logoutListener) {
  55. $logoutListenerPriority = $this->getListenerPriority($logoutListener);
  56. }
  57. foreach ($authenticationListeners as $listener) {
  58. $listenerPriority = $this->getListenerPriority($listener);
  59. // Yielding the LogoutListener at the correct position
  60. if (null !== $logoutListener && $listenerPriority < $logoutListenerPriority) {
  61. yield $logoutListener;
  62. $logoutListener = null;
  63. }
  64. yield $listener;
  65. }
  66. // When LogoutListener has the lowest priority of all listeners
  67. if (null !== $logoutListener) {
  68. yield $logoutListener;
  69. }
  70. };
  71. $this->callListeners($event, $authenticationListeners());
  72. }
  73. public function onKernelFinishRequest(FinishRequestEvent $event)
  74. {
  75. $request = $event->getRequest();
  76. if (isset($this->exceptionListeners[$request])) {
  77. $this->exceptionListeners[$request]->unregister($this->dispatcher);
  78. unset($this->exceptionListeners[$request]);
  79. }
  80. }
  81. /**
  82. * {@inheritdoc}
  83. */
  84. public static function getSubscribedEvents()
  85. {
  86. return [
  87. KernelEvents::REQUEST => ['onKernelRequest', 8],
  88. KernelEvents::FINISH_REQUEST => 'onKernelFinishRequest',
  89. ];
  90. }
  91. protected function callListeners(RequestEvent $event, iterable $listeners)
  92. {
  93. foreach ($listeners as $listener) {
  94. $listener($event);
  95. if ($event->hasResponse()) {
  96. break;
  97. }
  98. }
  99. }
  100. private function getListenerPriority(object $logoutListener): int
  101. {
  102. return $logoutListener instanceof FirewallListenerInterface ? $logoutListener->getPriority() : 0;
  103. }
  104. }