Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony: How do I refresh the authenticated user from the database?

Say for example I grant a new role to the currently authenticated user in a controller, like so:

$em = $this->getDoctrine()->getManager();
$loggedInUser = $this->get('security.context')->getToken()->getUser();
$loggedInUser->addRole('ROLE_XYZ');

$em->persist($loggedInUser);
$em->flush();

On the next page load, when I grab the authenticated user again:

$loggedInUser = $this->get('security.context')->getToken()->getUser();

They are not granted the role. I am guessing this is because the user is stored in the session and needs to be refreshed.

How do I do this?

I am using FOSUserBundle if that makes a difference.

EDIT: This question was originally asked in the context of Symfony version 2.3 but there are answers for more recent versions below as well.

like image 206
Nada_Surf Avatar asked Oct 31 '13 18:10

Nada_Surf


4 Answers

Try this:

$em = $this->getDoctrine()->getManager();
$loggedInUser = $this->get('security.context')->getToken()->getUser();
$loggedInUser->addRole('ROLE_XYZ');

$em->persist($loggedInUser);
$em->flush();

$token = new \Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken(
  $loggedInUser,
  null,
  'main',
  $loggedInUser->getRoles()
);

$this->container->get('security.context')->setToken($token);
like image 146
dmnptr Avatar answered Oct 17 '22 00:10

dmnptr


There's no need for the token reset in the previous answer. Just, in your security config file (security.yml, etc...), add this:

security:
    always_authenticate_before_granting: true
like image 32
Marc Avatar answered Oct 17 '22 00:10

Marc


While an answer is accepted, Symfony actually has a native way to refresh the User object. Credit goes out to Joeri Timmermans for this article.

Steps for refreshing the User object:

  1. Make your User entity implement the interface

Symfony\Component\Security\Core\User\EquatableInterface

  1. Implement the abstract function isEqualTo:

public function isEqualTo(UserInterface $user)
{
    if ($user instanceof User) {
        // Check that the roles are the same, in any order
        $isEqual = count($this->getRoles()) == count($user->getRoles());
        if ($isEqual) {
            foreach($this->getRoles() as $role) {
                $isEqual = $isEqual && in_array($role, $user->getRoles());
            }
        }
        return $isEqual;
    }

    return false;
}

The code above refreshes the User object if any new roles are added. The same principle also holds true for other fields you compare.

like image 14
Thomas Maurstad Larsson Avatar answered Oct 16 '22 23:10

Thomas Maurstad Larsson


$user = $this->getUser();
$userManager = $this->get('fos_user.user_manager');
$user->addRole('ROLE_TEACHER');
$userManager->updateUser($user);
$newtoken = new \Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken($user,null,'main', $user->getRoles());
$token = $this->get('security.token_storage')->setToken($newtoken);
like image 4
cretthie Avatar answered Oct 16 '22 23:10

cretthie