Creating your own security attribute with Symfony

Introduction

Symfony security has a great feature to check authorization named Voters. Voters are services which allows you to check user authorization in the way you need.
In this article, I would like to share with you another way to defin…


This content originally appeared on DEV Community and was authored by Nacho Colomina Torregrosa

Introduction

Symfony security has a great feature to check authorization named Voters. Voters are services which allows you to check user authorization in the way you need.
In this article, I would like to share with you another way to define custom authorization checking: Create our custom security attribute
Let’s imagine we store user roles out of the User class (the one which implements the Symfony UserInterface) and we have a controller on which we only want to allow ROLE_SUPERUSER users.

Creating the Attribute

Let’s create a simple attribute which receive the roles we want to allow

#[\Attribute]
class IsUserGranted
{
    public function __construct(public readonly array $roles){ }
}

Creating the Event Subscriber

Now, let’s create a subscriber which will keep listening to KernelEvents::CONTROLLER_ARGUMENTS.

class UserGrantedSubscriber implements EventSubscriberInterface
{

    public static function getSubscribedEvents(): array
    {
        return [
            KernelEvents::CONTROLLER_ARGUMENTS => ['onKernelControllerArguments']
        ];
    }

    public function onKernelControllerArguments(ControllerArgumentsEvent $event): void
    {
        $attrs = $event->getAttributes();

        /** @var IsUserGranted[]|null $isUserGrantedAttrs */
        $isUserGrantedAttrs = $attrs[IsUserGranted::class] ?? null;

        if(!$isUserGrantedAttrs){
            return;
        }

        $isUserGranted = $isUserGrantedAttrs[0];
        // Some code to get user roles from outside the User
        $roles = ['......'];

        // ------------------------------------

        $commonRoles = array_intersect(
            $roles,
            $isUserGranted->roles
        );

        if(count($commonRoles) === 0){
            throw new AccessDeniedException('You are not granted to get this resource');
        }
    }
}

After the KernelEvents::CONTROLLER_ARGUMENTS event is received, the function onKernelControllerArguments is executed. The function gets an object of class ControllerArgumentsEvent as a parameter. This object gives us access to controller attributes through the getAttributes method. If the IsUserGranted attribute is present, the user roles will be compared against granted roles and, if there are no matching roles, an AccessDeniedException will be thrown.

Protecting a Controller

The last step is to use our new attribute in a controller. Let’s create a controller and set it our attribute:

#[IsUserGranted(roles: ["ROLE_SUPERUSER"])]
class AdminController extends AbstractController
{
    #[Route('/admin/domains', name: 'get_admin_domains', methods: ['GET'])]
    public function getAdminDomains(): JsonResponse
    {
        return new JsonResponse([
            'ares.com',
            'atila.com',
        ], Response::HTTP_OK);
    }
}

And that’s all. If we try to access the resource with a user who does not have a ROLE_SUPERUSER, access will be denied.

Conclusion

This is another way you can consider if you want to add an extra authorization layer. As I've said in the introduction, this way can be useful when you want to apply the same authorization logic to all controller actions but the IsGranted attribute does not match your needs.

PHP attributes combined with the PHP reflection capabilities are a fantastic combination that allow developers to add extra behavior to classes in a really descriptive way. In my last published book, I use attributes to mark services as API operations, mark operations as background etc. If you want to know more, you can find the book here: [https://amzn.eu/d/3eO1DDi].


This content originally appeared on DEV Community and was authored by Nacho Colomina Torregrosa


Print Share Comment Cite Upload Translate Updates
APA

Nacho Colomina Torregrosa | Sciencx (2024-06-29T10:02:54+00:00) Creating your own security attribute with Symfony. Retrieved from https://www.scien.cx/2024/06/29/creating-your-own-security-attribute-with-symfony/

MLA
" » Creating your own security attribute with Symfony." Nacho Colomina Torregrosa | Sciencx - Saturday June 29, 2024, https://www.scien.cx/2024/06/29/creating-your-own-security-attribute-with-symfony/
HARVARD
Nacho Colomina Torregrosa | Sciencx Saturday June 29, 2024 » Creating your own security attribute with Symfony., viewed ,<https://www.scien.cx/2024/06/29/creating-your-own-security-attribute-with-symfony/>
VANCOUVER
Nacho Colomina Torregrosa | Sciencx - » Creating your own security attribute with Symfony. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2024/06/29/creating-your-own-security-attribute-with-symfony/
CHICAGO
" » Creating your own security attribute with Symfony." Nacho Colomina Torregrosa | Sciencx - Accessed . https://www.scien.cx/2024/06/29/creating-your-own-security-attribute-with-symfony/
IEEE
" » Creating your own security attribute with Symfony." Nacho Colomina Torregrosa | Sciencx [Online]. Available: https://www.scien.cx/2024/06/29/creating-your-own-security-attribute-with-symfony/. [Accessed: ]
rf:citation
» Creating your own security attribute with Symfony | Nacho Colomina Torregrosa | Sciencx | https://www.scien.cx/2024/06/29/creating-your-own-security-attribute-with-symfony/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.