我正在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:我需要一种方法可以在用户登录后更改用户的角色,而无需强制用户重新登录。
答案 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á一切都开始完美。
稍后我将把控制器上的代码移动到一个服务上,该服务也将被传递给帖子登录监听器,这样我只有一个游戏可以进行更改。
我真的不知道这是否是正确的方式,但是现在它似乎有效。