Kritim Yantra
Apr 18, 2025
Managing user access is crucial for web applications. Symfony provides a powerful role-based access control (RBAC) system to restrict what users can do.
In this guide, you’ll learn:
✅ How to define roles in Symfony
✅ Restricting routes by roles
✅ Creating custom permissions with voters
✅ Best practices for security
Let’s build a secure role-based system step by step!
Roles define user access levels (e.g., ROLE_USER
, ROLE_ADMIN
).
ROLE_USER
→ Basic authenticated user ROLE_ADMIN
→ Full accessIn the User
entity (generated by make:user
):
// src/Entity/User.php
#[ORM\Column(type: 'json')]
private array $roles = [];
public function getRoles(): array
{
$roles = $this->roles;
$roles[] = 'ROLE_USER'; // Every user has ROLE_USER by default
return array_unique($roles);
}
Edit a user in the database:
UPDATE user SET roles = '["ROLE_ADMIN"]' WHERE id = 1;
// src/Controller/RegistrationController.php
$user->setRoles(['ROLE_USER']); // Default role
$user->setRoles(['ROLE_ADMIN', 'ROLE_USER']);
security.yaml
# config/packages/security.yaml
security:
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/profile, roles: ROLE_USER }
// src/Controller/AdminController.php
use Symfony\Component\Security\Http\Attribute\IsGranted;
#[IsGranted('ROLE_ADMIN')]
public function adminDashboard(): Response
{
return $this->render('admin/dashboard.html.twig');
}
{% if is_granted('ROLE_ADMIN') %}
<a href="/admin">Admin Panel</a>
{% endif %}
Sometimes, roles aren’t enough (e.g., "Can this user edit this post?"). For fine-grained control, use Voters.
php bin/console make:voter
Name it PostVoter
.
Edit src/Security/Voter/PostVoter.php
:
protected function supports(string $attribute, mixed $subject): bool
{
return in_array($attribute, ['EDIT', 'DELETE']) && $subject instanceof Post;
}
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
{
$user = $token->getUser();
if (!$user instanceof User) return false;
$post = $subject;
return match ($attribute) {
'EDIT' => $user === $post->getAuthor() || in_array('ROLE_ADMIN', $user->getRoles()),
'DELETE' => in_array('ROLE_ADMIN', $user->getRoles()),
default => false,
};
}
#[IsGranted('EDIT', subject: 'post')]
public function edit(Post $post): Response
{
// Only the author or admin can edit
}
Define role hierarchy in security.yaml
:
security:
role_hierarchy:
ROLE_ADMIN: [ROLE_USER, ROLE_MODERATOR]
ROLE_MODERATOR: [ROLE_USER]
Now:
ROLE_MODERATOR
and ROLE_USER
. ROLE_USER
.$this->isGranted('ROLE_ADMIN'); // Returns true/false
$user = new User();
$user->setRoles(['ROLE_ADMIN']);
$this->client->loginUser($user);
🔹 Always use ROLE_
prefix (Symfony convention).
🔹 Prefer voters over multiple roles for complex rules.
🔹 Never store sensitive logic in Twig (handle in PHP).
🔹 Use $this->denyAccessUnlessGranted()
for quick checks.
You’ve now mastered Symfony’s role and permission system!
✅ Defined roles and restricted routes
✅ Created custom permissions with voters
✅ Used role hierarchy for inheritance
➡️ Try API tokens for stateless auth (lexik/jwt-authentication-bundle
)
➡️ Explore Symfony ACL for advanced permissions
No comments yet. Be the first to comment!
Please log in to post a comment:
Sign in with Google