相同用户,具有不同角色的多个帐户

时间:2016-10-11 19:04:09

标签: php symfony

我正在Symfony 3中创建一个具有以下结构的应用程序:

class Account {
    private $id;
    private $name;
}

class User {
    private $id;
    private $email;
    private $password;
}

class UserAccount {
    private $id;
    private $userId;
    private $roles;
}

正如我们所看到的,用户可以属于每个帐户具有不同角色的多个帐户,假设帐户1的角色为ROLE_ADMIN,而帐户2的角色为ROLE_EDITOR。

问题是用户将有一个可以更改帐户的选择框,这意味着需要根据会话上的值(因为帐户ID)从会话中加载角色

这也意味着当用户登录网站时,将没有角色,因为该角色由所选帐户决定。

我很难使用事件,但这似乎与我读过的内容不相符。

有没有人对此有任何想法/见解?

我有自己的自定义身份验证器,因为我需要同时支持MD5和bcrypt密码。

这意味着我有一个扩展Symfony的SimpleFormAuthenticatorInterface的类,这允许我让用户登录MD5并自动将它们升级到bcrypt。

我的用户模型(这是正常模式)和自定义身份验证器:Gist

要sumarize:我需要一种方法可以在用户登录后更改用户的角色,而无需强制用户重新登录。

1 个答案:

答案 0 :(得分:1)

经过两天的努力,这就是解决方案。

查看问题时,当用户登录时,需要根据UserAccount表中的内容确定角色,因为用户可以拥有多个与他关联的帐户,解决此问题的唯一方法是首先创建帖子登录监听器:

 /**
  * On login
  * 
  * @param  InteractiveLoginEvent        $event The login event
  * 
  * @return void
  */
  public function onSecurityInteractiveLogin(InteractiveLoginEvent $event) {
       $user = $this->tokenStorage->getToken()->getUser();
       // get the user accounts of the current from the database
       $accountsOfUser = $this->em->getRepository('AppBundle\Entity\AccountHasUser')->getAccountsOfUser($user->getId());
       foreach ( $accountsOfUser as $accountOfUser ) {
            $this->session->set('accountid', $accountOfUser['account_id']);
                $user->resetAndAddRole('ROLE_' . $accountOfUser['const']);
                break;
       }
       // We just need to set the new security token
       $token = new UsernamePasswordToken(
            $user,
            null,
           'main',
           $user->getRoles()
      );
      // Update the current token to set the new role
      $this->tokenStorage->setToken($token);
}

我知道我只能从数据库中获取一条记录,但这只是为了显示(不要盲目地将其复制/粘贴到您的代码中)。

所以基本上我得到了用户的第一个帐户,获得了它的角色,在会话中添加了帐号ID(仍然需要阅读更多关于Symfony会话中的包),然后继续生成一个新的UsernamePasswordToken并添加它到tokenStorage。

$ user-> resetAndAddRole,是我的用户模型中的一个函数,它只有以下内容:

/**
 * Resets current user roles and add's the new one
 * 
 * @param  string       $role       The role to add
 * 
 * @return AppBundle\Entity\User
 */
public function resetAndAddRole($role) {
    $this->roles = array($role);
    return $this;
}

现在我还需要允许用户在登录时更改帐户,因此在控制器中:

public function changeAccountAction(Request $request, $id) {
        $user = $this->get('security.token_storage')->getToken()->getUser();
        $em = $this->getDoctrine()->getManager();
        $newAccountRole = $em->getRepository('AppBundle\Entity\AccountHasUser')->getAccountModelByAccountIdANdUserId($id, $user->getId());
        $user->resetAndAddRole('ROLE_' . $newAccountRole['const']);
        $token = new UsernamePasswordToken(
            $user,
            null,
            'main',
            $user->getRoles()
        );
        // Update the current token to set the new role
        $this->get('security.token_storage')->setToken($token);
        $this->get('session')->set('accountid', $id);
        // $em = $this->getDoctrine()->getManager();
        // $accountsList = $em->getRepository('AppBundle\Entity\AccountHasUser')->getAccountsOfUser($user->getId());
        // We need to change the users roles right here and how to we do it?
        // We simply change the 

        return new RedirectResponse($this->generateUrl('dashboard'));
    }

基本上,获取通过参数传递的帐户,更改会话值,以便我们可以在查询和需要帐户ID的所有其他代码中使用它,然后创建新的UsernamePasswordToken和voilá一切都开始完美。

稍后我将把控制器上的代码移动到一个服务上,该服务也将被传递给帖子登录监听器,这样我只有一个游戏可以进行更改。

我真的不知道这是否是正确的方式,但是现在它似乎有效。