vendor/symfony/security-http/EventListener/IsGrantedAttributeListener.php line 39
- <?php
- /*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
- namespace Symfony\Component\Security\Http\EventListener;
- use Symfony\Component\EventDispatcher\EventSubscriberInterface;
- use Symfony\Component\ExpressionLanguage\Expression;
- use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
- use Symfony\Component\HttpFoundation\Request;
- use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent;
- use Symfony\Component\HttpKernel\Exception\HttpException;
- use Symfony\Component\HttpKernel\KernelEvents;
- use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
- use Symfony\Component\Security\Core\Exception\AccessDeniedException;
- use Symfony\Component\Security\Core\Exception\RuntimeException;
- use Symfony\Component\Security\Http\Attribute\IsGranted;
- /**
- * Handles the IsGranted attribute on controllers.
- *
- * @author Ryan Weaver <ryan@knpuniversity.com>
- */
- class IsGrantedAttributeListener implements EventSubscriberInterface
- {
- public function __construct(
- private readonly AuthorizationCheckerInterface $authChecker,
- private ?ExpressionLanguage $expressionLanguage = null,
- ) {
- }
- public function onKernelControllerArguments(ControllerArgumentsEvent $event)
- {
- /** @var IsGranted[] $attributes */
- if (!\is_array($attributes = $event->getAttributes()[IsGranted::class] ?? null)) {
- return;
- }
- $request = $event->getRequest();
- $arguments = $event->getNamedArguments();
- foreach ($attributes as $attribute) {
- $subject = null;
- if ($subjectRef = $attribute->subject) {
- if (\is_array($subjectRef)) {
- foreach ($subjectRef as $refKey => $ref) {
- $subject[\is_string($refKey) ? $refKey : (string) $ref] = $this->getIsGrantedSubject($ref, $request, $arguments);
- }
- } else {
- $subject = $this->getIsGrantedSubject($subjectRef, $request, $arguments);
- }
- }
- if (!$this->authChecker->isGranted($attribute->attribute, $subject)) {
- $message = $attribute->message ?: sprintf('Access Denied by #[IsGranted(%s)] on controller', $this->getIsGrantedString($attribute));
- if ($statusCode = $attribute->statusCode) {
- throw new HttpException($statusCode, $message);
- }
- $accessDeniedException = new AccessDeniedException($message);
- $accessDeniedException->setAttributes($attribute->attribute);
- $accessDeniedException->setSubject($subject);
- throw $accessDeniedException;
- }
- }
- }
- public static function getSubscribedEvents(): array
- {
- return [KernelEvents::CONTROLLER_ARGUMENTS => ['onKernelControllerArguments', 20]];
- }
- private function getIsGrantedSubject(string|Expression $subjectRef, Request $request, array $arguments): mixed
- {
- if ($subjectRef instanceof Expression) {
- $this->expressionLanguage ??= new ExpressionLanguage();
- return $this->expressionLanguage->evaluate($subjectRef, [
- 'request' => $request,
- 'args' => $arguments,
- ]);
- }
- if (!\array_key_exists($subjectRef, $arguments)) {
- throw new RuntimeException(sprintf('Could not find the subject "%s" for the #[IsGranted] attribute. Try adding a "$%s" argument to your controller method.', $subjectRef, $subjectRef));
- }
- return $arguments[$subjectRef];
- }
- private function getIsGrantedString(IsGranted $isGranted): string
- {
- $processValue = fn ($value) => sprintf($value instanceof Expression ? 'new Expression("%s")' : '"%s"', $value);
- $argsString = $processValue($isGranted->attribute);
- if (null !== $subject = $isGranted->subject) {
- $subject = !\is_array($subject) ? $processValue($subject) : array_map(function ($key, $value) use ($processValue) {
- $value = $processValue($value);
- return \is_string($key) ? sprintf('"%s" => %s', $key, $value) : $value;
- }, array_keys($subject), $subject);
- $argsString .= ', '.(!\is_array($subject) ? $subject : '['.implode(', ', $subject).']');
- }
- return $argsString;
- }
- }