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

Jov*_*vic 3 session acl symfony

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

这里有一个问题:我希望该用户能够app1通过访问www.myproject.com/app1/login和更改URL后登录到/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();
    }
}
Run Code Online (Sandbox Code Playgroud)

用户#平等(的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;
Run Code Online (Sandbox Code Playgroud)

}

Sgo*_*kes 5

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

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

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

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

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

我不认为symfony2是这里的大问题,而是整个处理用php.让我们想一想没有symfony2我会建议的:

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

user.app1 = array('username','password',array('role1','role2'))
Run Code Online (Sandbox Code Playgroud)

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

我查了symfony 安全参考,你有一些扩展点,所以也许你可以在那里工作.在form_login得到了success_handler,所以加入数组作为上述建议应在那里进行会话.防火墙本身具有一定的参数,如request_matcherentry_point其可用于添加额外的检查像我上面提到的那些.所有都被定义为服务,因此注入实体管理器和安全上下文应该没有问题.

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