sajad torkamani

Symfony authorization = roles

Symfony’s authorization system is based on roles and is essentially is a two-step process:

  • You assign one or more roles to a given user.
  • You grant/deny access to resources (e.g., URLs or files) based on the user’s roles.

Roles in action

You’ll want to add a user.roles column which contains a JSON array of role names. So something like:

// src/Entity/User.php

// ...
class User
{
    #[ORM\Column(type: 'json')]
    private array $roles = [];

    // ...
    public function getRoles(): array
    {
        $roles = $this->roles;
        // guarantee every user at least has ROLE_USER
        $roles[] = 'ROLE_USER';

        return array_unique($roles);
    }
}

You can then grant / deny access based on the roles via:

  1. Access control rules in security.yaml
  2. Custom logic in your controller code
  3. Attributes

1. Access control rules

# config/packages/security.yaml
security:
    # ...

    firewalls:
        # ...
        main:
            # ...

    access_control:
        # require ROLE_ADMIN for /admin*
        - { path: '^/admin', roles: ROLE_ADMIN }

        # or require ROLE_ADMIN or IS_AUTHENTICATED_FULLY for /admin*
        - { path: '^/admin', roles: [IS_AUTHENTICATED_FULLY, ROLE_ADMIN] }

        # the 'path' value can be any valid regular expression
        # (this one will match URLs like /api/post/7298 and /api/comment/528491)
        - { path: ^/api/(post|comment)/\d+$, roles: ROLE_USER }

2. Controller code

// src/Controller/AdminController.php
// ...

public function adminDashboard(): Response
{
    $this->denyAccessUnlessGranted('ROLE_ADMIN');

    // or add an optional message - seen by developers
    $this->denyAccessUnlessGranted('ROLE_ADMIN', null, 'User tried to access a page without having ROLE_ADMIN');
}

3. Attributes

// src/Controller/AdminController.php
// ...

use Symfony\Component\Security\Http\Attribute\IsGranted;

#[IsGranted('ROLE_ADMIN')]
class AdminController extends AbstractController
{
    // Optionally, you can set a custom message that will be displayed to the user
    #[IsGranted('ROLE_SUPER_ADMIN', message: 'You are not allowed to access the admin dashboard.')]
    public function adminDashboard(): Response
    {
        // ...
    }
}

If access isn’t granted, a AccessDeniedException will be thrown.

Other notes

Role hierarchy

You can create role hierarchies using config/packages/security.yaml:

# config/packages/security.yaml
security:
    # ...

    role_hierarchy:
        ROLE_ADMIN:       ROLE_USER
        ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]

In the example config from above:

  • Users with the role ROLE_ADMIN will have the role ROLE_USER
  • Users with the role ROLE_SUPER_ADMIN will have the role ROLE_ADMIN, ROLE_ROLE_ALLOWED_TO_SWITCH, and ROLE_USER

Links

Tagged: Symfony