【问题标题】:Symfony2 shared users across multiple appsSymfony2 跨多个应用共享用户
【发布时间】:2012-03-20 03:52:18
【问题描述】:

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

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

我真的看不到 refreshUser() 何时被调用... :-/

所有应用都使用相同的UserRole 实体和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();
    }
}

User#equals(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;

}

【问题讨论】:

    标签: session symfony acl


    【解决方案1】:

    你的问题让我想到了。 当使用 symfony2 安全性时,你遇到了一个问题:要么会话有效,即用户被验证为匿名用户或真实用户,要么会话无效。

    因此,考虑到这一点,我看不到您的方法按您希望的那样工作,因为假设 user1 登录并正在使用 app1。现在他切换到 app2 并且不在数据库中,这意味着他应该没有访问权限。现在要做什么?使会话无效?这意味着他必须在 app1 中重新登录。

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

    还有一个问题:好像symfony2把用户的id存到session里面了,所以没有访问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 防止用户查看“错误”内容。

    【讨论】:

    • 谢谢嘘!在过去的几天里,我一直在对此进行一些研究,在阅读了您的回答后,我意识到我将不得不放弃我想象的整个想法。但是,您关于使用防火墙服务点的想法非常有趣,值得研究。我可能迟早要进行代码重构......毕竟 Symfony 官方文档不鼓励单独的应用程序,而是捆绑。无论如何,非常感谢您提供如此详细的解释和非常有用的建议。 :)
    猜你喜欢
    • 2017-04-12
    • 2016-03-12
    • 1970-01-01
    • 2012-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-16
    • 1970-01-01
    相关资源
    最近更新 更多