Symfony2在多个应用程序中共享用户

时间:2012-03-12 18:18:46

标签: session symfony acl

我有多个共享公共实体的symfony2应用程序,但使用不同的数据库设置。每个数据库都有表useruser_rolerole

以下是问题:我希望该用户能够通过访问app1并在将网址更改为www.myproject.com/app1/login后使用现有令牌来登录/app2/ 如果app2的数据库中存在相同的用户(相同的用户名,密码和盐)。 目前它仅检查相同的用户名,您必须同意,这非常不方便......

我无法确定何时调用refreshUser() ...: - /

所有应用使用相同的UserRole实体以及UserRepository

非常感谢任何帮助!

UserRepository:

class UserRepository extends EntityRepository implements \Symfony\Component\Security\Core\User\UserProviderInterface{
    /** @var User */
    private $user;

    public function loadUserByUsername($username) {
        /** @var $Q \Doctrine\ORM\Query */
        $Q = $this->getEntityManager()
        ->createQuery('SELECT u FROM CommonsBundle:User u WHERE u.username = :username')
        ->setParameters(array(
            'username' => $username
        ));
        $user = $Q->getOneOrNullResult();
        if ( $user == null ){
            throw new UsernameNotFoundException("");
        }
        return $this->user = $user;
    }

    public function refreshUser(UserInterface $user) {
        return $this->loadUserByUsername($user->getUsername());
    }

    public function supportsClass($class) {
        return $class === 'CommonsBundle\Entity\User';
    }

    public function findById($id){
        return $this->getEntityManager()
            ->createQuery('SELECT u FROM CommonsBundle:User u WHERE u.id = :id')
            ->setParameters(array(
            'id' => $id
            ))
            ->getOneOrNullResult();
    }
}

用户#等于(的UserInterface):

我知道有一种比较漂亮的方法来编写这个方法,但我会在看到这个工作后重写它:)

public function equals(UserInterface $user)
{
    if (!$user instanceof User) {
          return false;
    }
    if ($this->password !== $user->getPassword()) {
          return false;
    }

    if ($this->getSalt() !== $user->getSalt()) {
          return false;
    }

    if ($this->username !== $user->getUsername()) {
          return false;
    }

    return true;

}

1 个答案:

答案 0 :(得分:5)

您的问题让我思考。使用symfony2安全性时,您遇到一个问题:会话有效,意味着用户被认证为匿名用户或真实用户,或者会话无效。

所以,考虑到这一点,我没有看到你的方法按照你的意愿工作,因为让我们说user1登录并使用app1。现在他切换到app2并且不在数据库中,这意味着他不应该访问。现在做什么?使会话无效?这意味着他必须再次登录app1。

如果您要使用子域,则可以将会话绑定到该子域,但这意味着用户必须再次为每个应用程序登录。

还有另一个问题:似乎symfony2将用户的id存储到会话中,因此无法访问app1数据库,您无法知道app1数据库中用户的密码和角色是什么,无法检查为了它。

我猜symfony2的安全性根本就不是针对这种行为的。它希望会话与整个应用程序中的同一用户相关。

我认为symfony2不是这里的大问题,而是用php进行整体处理。让我们思考一下如果没有symfony2我会建议:

当用户登录时,将用户和角色存储到会话中的特定阵列中,例如:

user.app1 = array('username','password',array('role1','role2'))

现在,在每次向app1发出请求时,我会检查user.app1是否在会话中并从那里读取角色。如果没有,我会检查user.app2,user.app3等。如果我找不到,请重定向登录。如果我找到一个,我会查询数据库以找到具有相同用户名的用户并比较其他值。如果匹配,将所有内容存储到数据库中。如果没有,请从会话中检查下一位用户。

我抬起了symfony security reference,你有一些扩展点,所以也许你可以从那里开始工作。 form_login获得了success_handler,因此应该在此处将数组添加到会话中。防火墙本身有一些参数,如request_matcherentry_point,可以用来添加我上面提到的其他检查。所有都被定义为服务,因此注入实体管理器和安全上下文应该没问题。

我个人认为设计本身并不是最优的,您可能更好地重构代码,以便为所有应用程序和不同角色使用一个用户(请记住,您可以定义许多实体管理器并使用不同的数据库)甚至整合所有数据库并将所有内容存储到一个数据库中,使用acl防止用户查看“错误”的内容。