Security
The Security component answers two questions. Authentication (who you are): firewall, user provider, authenticator. Authorization (what you're allowed to do): roles, access_control and voters. You write the user classes yourself: make:user creates a User entity with UserInterface.
Symfony · config/packages/security.yaml
security:
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: auto
providers:
users:
entity: { class: App\Entity\User, property: email }
role_hierarchy:
ROLE_ADMIN: [ROLE_FAQ_EDITOR]
firewalls:
dev:
pattern: ^/(_profiler|_wdt|assets)/
security: false
main:
lazy: true
provider: users
form_login:
login_path: app_login
check_path: app_login
enable_csrf: true
logout:
path: app_logout
access_control:
- { path: ^/admin, roles: ROLE_FAQ_EDITOR }
- { path: ^/account, roles: ROLE_USER }
Magento · acl.xml + ADMIN_RESOURCE
<acl>
<resources>
<resource id="Magento_Backend::admin">
<resource id="Vendor_Faq::faq" title="FAQ">
<resource id="Vendor_Faq::question_edit"
title="Edit questions"/>
</resource>
</resource>
</resources>
</acl>
class Edit extends Action
{
const ADMIN_RESOURCE = 'Vendor_Faq::question_edit';
}
Symfony · Voter + #[IsGranted]
final class QuestionVoter extends Voter
{
protected function supports(string $attribute, mixed $subject): bool
{
return $attribute === 'QUESTION_EDIT' && $subject instanceof Question;
}
protected function voteOnAttribute(
string $attribute,
mixed $subject,
TokenInterface $token,
?Vote $vote = null,
): bool
{
$user = $token->getUser();
return $user instanceof User
&& ($user->hasRole('ROLE_ADMIN') || $subject->getAuthor() === $user);
}
}
#[Route('/admin/questions/{id}/edit', name: 'admin_question_edit')]
#[IsGranted('QUESTION_EDIT', subject: 'question')]
public function edit(Question $question, Request $request): Response
Roles decide general access, voters decide access to a specific object ("the author can edit their own question"). Magento's ACL has no such granularity. The ?Vote $vote argument appeared in 7.3; in older versions the signature doesn't have it. For APIs you usually take the access_token authenticator or a JWT bundle instead of integration tokens.