【问题标题】:Symfony: How do I refresh the authenticated user from the database?Symfony:如何从数据库中刷新经过身份验证的用户?
【发布时间】:2013-11-11 21:19:58
【问题描述】:

例如,我将一个新角色授予控制器中当前经过身份验证的用户,如下所示:

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

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

在下一页加载时,当我再次获取经过身份验证的用户时:

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

他们没有被授予角色。我猜这是因为用户存储在会话中,需要刷新。

我该怎么做?

如果有什么不同,我正在使用 FOSUserBundle。

编辑:这个问题最初是在 Symfony 2.3 版的上下文中提出的,但下面也有更新版本的答案。

【问题讨论】:

  • 数据库更新了吗?
  • 是的,数据库已更新。因此,如果我注销并再次登录,则会反映新角色。
  • 我正在使用if is_granted('ROLE_XYZ') 在树枝模板中检查新角色。我将其更改为if app.user.hasRole('ROLE_XYZ'),现在它正在工作。奇怪...
  • @Nada_Surf - 这是因为 hasRole 检查确切的角色。它忽略角色层次结构.. 例如:是 ROLE_SUPER_ADMIN 有 ROLE_USER, ROLE_ADMIN.. 如果你检查 hasRole('ROLE_ADMIN')--- false,hasGranted('ROLE_ADMIN')--- true
  • 感谢 Alex,不过,一旦我退出并重新登录,对 is_granted('ROLE_XYZ') 的调用确实会返回 TRUE。

标签: php symfony fosuserbundle


【解决方案1】:

在 Symfony 4 中

public function somename(ObjectManager $om, TokenStorageInterface $ts)
    {
        $user = $this->getUser();
        if ($user) {
            $user->setRoles(['ROLE_VIP']); //change/update role
            // persist if need
            $om->flush();
            $ts->setToken(
                new PostAuthenticationGuardToken($user, 'main', $user->getRoles())
            );
            //...
        } else {
            //...
        }
    }

【讨论】:

    【解决方案2】:
    $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);
    

    【讨论】:

    • security.context 对我来说在 Symfony 4 中不起作用,但 security.token_storage 做到了。谢谢!
    【解决方案3】:

    虽然接受了答案,但 Symfony 实际上有一种本地方式来刷新用户对象。归功于 this article 的 Joeri Timmermans。

    刷新用户对象的步骤:

    1. 让您的用户实体实现接口

    Symfony\Component\Security\Core\User\EquatableInterface

    1. 实现抽象函数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;
    }

    如果添加了任何新角色,上面的代码会刷新 User 对象。同样的原则也适用于您比较的其他领域。

    【讨论】:

    • 谢谢!,直到现在我都不懂 EquatableInterface!
    • 仅供参考:如果您实现EquatableInterface,您可能还想添加 Symfony 通常会进行的其他比较(直到您实现 EquatableInterface)。如果您的用户还实现了 AdvancedUserInterface,那么您可能需要为 isAccountNonExpiredisAccountNonLockedisCredentialsNonExpiredisEnabled 添加比较。查看github.com/symfony/security/blob/v3.1.2/Core/Authentication/…
    • 仅供参考:AdvancedUserInterface 现在已弃用,取而代之的是 UserChecker
    【解决方案4】:

    上一个答案中不需要重置令牌。只需在您的安全配置文件(security.yml 等)中添加:

    security:
        always_authenticate_before_granting: true
    

    【讨论】:

    • 如果这是与另一个答案相关的一点,我认为它更适合作为对该答案的评论,而不是它自己的答案
    • 显然你需要一些声誉才能做到这一点。智能四处走动。
    【解决方案5】:

    试试这个:

    $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);
    

    【讨论】:

    • 谢谢!正如您所展示的,诀窍是用具有新角色的新令牌替换安全令牌。
    • 我可以确认这个解决方案在 2.6.3 上仍然有效
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-29
    • 1970-01-01
    • 2017-09-11
    • 2019-09-27
    • 2020-11-15
    相关资源
    最近更新 更多