symfony/security-core
Symfony Security Core provides the foundation for authentication tokens, roles, voters, role hierarchies, and access decision management. Use it to build flexible authorization logic decoupled from user providers and integrate fine-grained access checks into apps.
To integrate symfony/security-core into a Laravel project, start by installing the package:
composer require symfony/security-core
Leverage the AccessDecisionManager to check user permissions in controllers or services:
use Symfony\Component\Security\Core\Authorization\AccessDecisionManager;
use Symfony\Component\Security\Core\Authorization\Voter\RoleVoter;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Role\RoleHierarchy;
// Initialize components
$roleHierarchy = new RoleHierarchy(['ROLE_ADMIN' => ['ROLE_USER']]);
$accessDecisionManager = new AccessDecisionManager([
new RoleVoter($roleHierarchy),
]);
// Simulate a logged-in user
$user = new \App\Models\User(['roles' => ['ROLE_ADMIN']]);
$token = new UsernamePasswordToken($user, 'main', $user->getRoles());
// Check if user has access
if (!$accessDecisionManager->decide($token, ['ROLE_ADMIN'])) {
abort(403, 'Unauthorized');
}
AuthenticationTrustResolver, TokenStorage, and UserChecker for user validation.AccessDecisionManager with Voter classes (e.g., RoleVoter, AuthenticatedVoter).UserProviderInterface for custom user loading logic.RoleHierarchy to establish role inheritance (e.g., ROLE_ADMIN inherits ROLE_USER).Voter for custom authorization logic:
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
class CustomVoter extends Voter {
protected function supports(string $attribute, mixed $subject): bool {
return $attribute === 'EDIT_POST';
}
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool {
return $token->getUser()->canEditPost($subject);
}
}
AccessDecisionManager:
$accessDecisionManager = new AccessDecisionManager([
new RoleVoter($roleHierarchy),
new CustomVoter(),
]);
UsernamePasswordToken or AnonymousToken for authentication:
$token = new UsernamePasswordToken($user, 'main', $user->getRoles(), [
'firewall' => 'admin',
]);
TokenStorage implementation:
$tokenStorage = new SessionTokenStorage(new NativeSession());
$tokenStorage->setToken($token);
$token = $tokenStorage->getToken();
if (!$token || !$token->isAuthenticated()) {
abort(401);
}
Create a middleware to wrap Symfony’s security logic:
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
class AuthenticateMiddleware {
public function __construct(private TokenStorageInterface $tokenStorage) {}
public function handle($request, Closure $next) {
$token = $this->tokenStorage->getToken();
if (!$token || !$token->isAuthenticated()) {
return redirect()->route('login');
}
return $next($request);
}
}
Implement UserProviderInterface for custom user loading (e.g., from a database):
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
class EloquentUserProvider implements UserProviderInterface {
public function loadUserByIdentifier(string $identifier): UserInterface {
return User::where('email', $identifier)->firstOrFail();
}
public function refreshUser(UserInterface $user): UserInterface {
return $this->loadUserByIdentifier($user->getUserIdentifier());
}
public function supportsClass(string $class): bool {
return User::class === $class;
}
}
Token Serialization:
__serialize()/__unserialize() methods.AbstractToken instead of implementing from scratch:
class CustomToken extends AbstractToken { ... }
Role Hierarchy Caching:
RoleHierarchy caches role mappings. Clear the cache if roles change dynamically:
$roleHierarchy->clearCache();
Impersonation Issues:
ImpersonatingToken and ensure the original token is preserved:
$impersonatingToken = new ImpersonatingToken($originalToken, $impersonatedUser);
Voter Order Matters:
AuthenticatedVoter) before broader ones (e.g., RoleVoter).AccessDecisionManager::setDecisionStrategy() to customize the voting strategy (e.g., AffirmativeStrategy for majority approval).Deprecated Methods:
eraseCredentials() (deprecated in Symfony 7.3). Use UserInterface::getRoles() without sensitive data.Enable Debugging:
SYMFONY_DEBUG=1 to log voter decisions and token states.$accessDecisionManager->setLogger(new \Monolog\Logger('security'));
Inspect Tokens:
dd($token->getRoles(), $token->getAttributes());
Role Hierarchy Visualization:
RoleHierarchy dumper to visualize role inheritance:
$roleHierarchy->dump();
Custom Voters:
Voter for attribute-based authorization (e.g., IS_OWNER):
class OwnerVoter extends Voter {
protected function supports(string $attribute, mixed $subject): bool {
return $attribute === 'IS_OWNER';
}
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool {
return $subject->getUserId() === $token->getUser()->id;
}
}
Token Attributes:
$token = new UsernamePasswordToken($user, 'main', $user->getRoles(), [
'department' => 'engineering',
]);
$department = $token->getAttribute('department');
Event Listeners:
SecurityEvents (e.g., INTERACTIVE_LOGIN) for post-authentication logic:
$dispatcher->addListener(SecurityEvents::INTERACTIVE_LOGIN, function (InteractiveLoginEvent $event) {
// Log or notify on login
});
Remember-Me Cookies:
RememberMeServices for persistent logins:
$rememberMeServices = new RememberMeServices(
$tokenStorage,
new PersistentTokenBasedRememberMeServices(
$cookieName,
$tokenStorage,
new PersistentTokenRepository(),
new PersistentToken($user->getUserIdentifier(), $secret),
new \DateTime('+30 days'),
true // Always remember
)
);
Session Integration:
SessionTokenStorage works with Laravel’s session driver by default. Ensure session configuration matches:
'session' => [
'driver' => 'file', // or 'database', 'redis', etc.
],
CSRF Protection:
CsrfTokenManager can conflict with Laravel’s built-in CSRF. Disable one or the other:
// Disable Laravel's CSRF middleware if using Symfony's
$middleware->remove(\App\Http\Middleware\VerifyCsrfToken::class);
User Model Mapping:
User model implements UserInterface and maps to Symfony’s expected methods:
class User implements UserInterface {
public function getRoles(): array { ... }
public function getPassword(): string { ... }
public function getUserIdentifier(): string { ... }
}
How can I help you explore Laravel packages today?