I'm working on a PHP application where there are two levels of authorizations.
On the first and classic level : the user logs in the application, the authentication system sets his roles and registers them in the auth token all right. Let's say out user has ROLE_USER and ROLE_ADMIN.
Now, for some reason I've been asked to dynamically add another role after authentication...
After the official documentation : https://symfony.com/doc/5.4/security/user_providers.html#creating-a-custom-user-provider I tried to achieve this with a custom user provider :
security.yaml :
providers:
users_in_memory: { memory: null }
app_user_provider:
id: App\Security\UserProvider
The UserProvider class has its refreshUser() method called with every request :
class UserProvider implements UserProviderInterface, PasswordUpgraderInterface
{
//...
public function refreshUser(UserInterface $user): UserInterface|User
{
if (!$user instanceof User) {
throw new UnsupportedUserException('nope');
}
$refreshedUser = $this->userRepository->find($user->getId());
if (!$refreshedUser) {
throw new UserNotFoundException('nope nope');
}
$refreshedUser->addRole('ROLE_BONUS'); // new role added !
return $refreshedUser;
}
}
Of course, the User class implements the EquatableInterface so the user is not de-authenticated and logged out by Symfony after the refresh.
Unfortunately, even if the auth token has refreshed its user as expected, it has not refreshed the list of roles given by AbstractToken::getRoleNames(). And when I check the granted new role in a controller, the check fails :
class DashboardInfosController extends AbstractController
{
public function renderPageWithBonusRole(): Response
{
$user = $this->getUser(); // this is the refreshed user
$roles = $user->getRoles(); // gives the correct roles, including ROLE_BONUS
$test = $this->isGranted('ROLE_BONUS'); // fails : only ROLE_USER & ROLE_ADMIN are checked here
return $this->render('site/_mypartial.html.twig');
}
}
After the code I see in the AbstractToken class, rolenames are only set in the constructor and never updated after this point. I've been struggling with this for a day and more, now, and still stuck... So, how can I tell the Security layer of Symfony 5.4 that it has to check the new roles list for my user ?