-->

当用户角色刷新,以及如何给力呢?(When are user roles refreshed and

2019-07-04 20:57发布

首先,我没有使用FOSUserBundle,我不能,因为我移植有其自身的模型层(无主义/蒙戈/任何在这里)等非常自定义行为的遗留系统。

我想我的遗产的角色系统的Symfony的连接,所以我可以在控制器和视图使用本地symfony的安全性。

我的第一次尝试加载并返回该用户的所有角色中的getRoles()从方法Symfony\Component\Security\Core\User\UserInterface 。 起初,它看起来像工作。 再从更深层面看后,我注意到,这些角色只有刷新时,用户登录这意味着,如果授予或吊销用户角色,他将不得不注销并重新登录以使更改生效。 不过,如果我撤销安全角色从一个用户,我想,要立即应用,这样的行为是不能接受我。

我想要的Symfony做的是重新加载每个请求的用户的角色,以确保他们跟上时代的。 我实现了一个自定义的用户提供其refreshUser(UserInterface $user)方法被调用每个请求,但不知何故角色没有被刷新。

代码加载/刷新我的UserProvider用户看起来是这样的:

public function loadUserByUsername($username) {
    $user = UserModel::loadByUsername($username); // Loads a fresh user object including roles!
    if (!$user) {
        throw new UsernameNotFoundException("User not found");
    }
    return $user;
}

refreshUser比较相似)

有没有一种方法,使每个请求的Symfony刷新用户角色吗?

Answer 1:

所以经过几天的努力找到一个可行的解决方案,并促进了Symfony2的用户邮件列表,我终于找到了。 下面已经从讨论中得出的https://groups.google.com/d/topic/symfony2/NDBb4JN3mNc/discussion

事实证明,有一个接口Symfony\Component\Security\Core\User\EquatableInterface是不适合的对象身份,但恰恰比较

如果测试两个对象是在安全和重新认证上下文等

实现你的用户类接口(一个已经实现UserInterface )。 实施所需的唯一方法isEqualTo(UserInterface $user) ,这样,如果当前用户的角色不同于传递用户的不同返回false。

注:用户对象是在会话序列化。 因为这样系列化作品的,请务必将角色存储在用户对象的字段,并且不直接在检索它们getRoles()方法,否则,所有的这是行不通的!

下面是具体的方法如何可能看起来像一个例子:

protected $roles = null;

public function getRoles() {

    if ($this->roles == null) {
        $this->roles = ...; // Retrieve the fresh list of roles
                            // from wherever they are stored here
    }

    return $this->roles;
}

public function isEqualTo(UserInterface $user) {

    if ($user instanceof YourUserClass) {
        // 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;
}

另外,还要注意的是,当角色的真正改变和重新载入页面,分析器工具栏可能会告诉你,你的用户没有通过验证。 此外,寻找到的探查,你可能会发现角色实际上并没有得到刷新。

我发现这个角色其实清爽工作。 只是,如果没有授权约束被击中(无@Secure注释,无需在防火墙等角色),刷新实际上没有完成,用户保存在“未”状态。

只要你打在执行任何类型的授权检查的页面,用户角色被刷新,并剖析工具栏显示有绿点和“验证:是”用户再次。

这对我来说是可以接受的行为 - 希望这是有益的:)



Answer 2:

在您的security.yml(或替代):

security:
    always_authenticate_before_granting: true

我的生活的最简单的游戏。



Answer 3:

从控制器,添加角色给用户,并保存到数据库后,只需拨打:

// Force refresh of user roles
$token = $this->get('security.context')->getToken()->setAuthenticated(false);


Answer 4:

看看这里 ,设置always_authenticate_before_grantingtruesecurity.yml



Answer 5:

我实现通过实现我自己的EntityUserProvider和压倒一切的loadByUsername($用户名)方法,此行为:

   /**
    * Load an user from its username
    * @param string $username
    * @return UserInterface
    */
   public function loadUserByUsername($username)
   {
      $user = $this->repository->findOneByEmailJoinedToCustomerAccount($username);

      if (null === $user)
      {
         throw new UsernameNotFoundException(sprintf('User "%s" not found.', $username));
      }

      //Custom function to definassigned roles to an user
      $roles = $this->loadRolesForUser($user);

      //Set roles to the user entity
      $user->setRoles($roles);

      return $user;
   }

诀窍是调用setRoles你打电话,每次loadByUsername ...希望它可以帮助



Answer 6:

解决办法是挂在学说postUpdate事件的订户。 如果有更新的实体是用户,因为登录同一用户,那我用的AuthenticationManager服务认证。 你必须注入服务容器(或相关服务)到用户的,当然。 我更愿意注入整个容器,以防止循环引用的问题。

public function postUpdate(LifecycleEventArgs $ev) {
    $entity = $ev->getEntity();

    if ($entity instanceof User) {
        $sc = $this->container->get('security.context');
        $user = $sc->getToken()->getUser();

        if ($user === $entity) {
            $token = $this->container->get('security.authentication.manager')->authenticate($sc->getToken());

            if ($token instanceof TokenInterface) {
                $sc->setToken($token);
            }
        }
    }
}


Answer 7:

对不起,我不能在评论,所以我重播质疑答复。 如果有人在symfony的安全性的新尝试让角色刷新工作的自定义密码验证,然后内部功能authenticateToken:

if(count($token->getRoles()) > 0 ){
        if ($token->getUser() == $user ){
            $passwordValid=true;
        }
    }

不要检查从DB / LDAP或任何密码。 如果用户系统进来,然后在$令牌只是用户名,也没有作用。



Answer 8:

现在的Symfony 4.1是在这里一段时间,
我通过解决问题手动认证用户 。



文章来源: When are user roles refreshed and how to force it?