Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/275.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP Websocket在测试中对用户进行身份验证(通过会话cookie)_Php_Symfony_Testing_Websocket_Ratchet - Fatal编程技术网

PHP Websocket在测试中对用户进行身份验证(通过会话cookie)

PHP Websocket在测试中对用户进行身份验证(通过会话cookie),php,symfony,testing,websocket,ratchet,Php,Symfony,Testing,Websocket,Ratchet,我正在尝试测试一个场景,一方面,匿名用户应该立即与Websocket连接断开连接,另一方面,经过身份验证的用户应该留在Websocket连接中。通过使用下面的代码,第一种情况很容易测试。身份验证过程不起作用 对于会话存储,我将Cookie身份验证与数据库结合使用:。这一切都很好,但是当涉及到使用身份验证来测试所描述的行为时,我不知道如何在测试中对用户进行身份验证。作为一个客户,我使用的是如下所示: \Ratchet\Client\connect('ws://127.0.0.1:8080')-&g

我正在尝试测试一个场景,一方面,匿名用户应该立即与Websocket连接断开连接,另一方面,经过身份验证的用户应该留在Websocket连接中。通过使用下面的代码,第一种情况很容易测试。身份验证过程不起作用

对于会话存储,我将Cookie身份验证与数据库结合使用:。这一切都很好,但是当涉及到使用身份验证来测试所描述的行为时,我不知道如何在测试中对用户进行身份验证。作为一个客户,我使用的是如下所示:

\Ratchet\Client\connect('ws://127.0.0.1:8080')->then(function($conn) {
    $conn->on('message', function($msg) use ($conn) {
        echo "Received: {$msg}\n";
    });

    $conn->send('Hello World!');
}, function ($e) {
    echo "Could not connect: {$e->getMessage()}\n";
});
我知道,作为第三个参数,我可以将头信息传递给“connect”方法,但我找不到一种方法,以便在ws-handshake期间连接客户端并正确传递cookie。我想到了这样的事情:

  • 通过创建
  • 我使用序列化用户在数据库的会话表中创建一个新条目
  • 我将创建的cookie作为第三个参数传递给connect方法
  • 这是我认为可行的理论,但用户在websocket端总是保持匿名。以下是迄今为止理论的代码:

    // ...
    use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
    
    class WebsocketTest extends WebTestCase
    {
    
        static $closed;
    
        protected function setUp()
        {
          self::$closed = null;
        }
    
    
        public function testWebsocketConnection()
        {
          $loop = Factory::create();
          $connector = new Connector($loop);
    
          // This user exists in database user tbl
          $symfClient = $this->createSession("testuser@test.com");
    
          $connector('ws://127.0.0.1:80', [], ['Origin' => 'http://127.0.0.1', 'Cookie' => 
                     $symfClient->getContainer()->get('session')->getName() . '=' 
                    . $symfClient->getContainer()->get('session')->getId()])
            ->then(function(WebSocket $conn) use($loop){
    
                $conn->on('close', function($code = null, $reason = null) use($loop) {
                    self::$closed = true;
                    $loop->stop();
                });
                self::$closed = false;
    
            }, function(\Exception $e) use ($loop) {
                $this->fail("Websocket connection failed");
                $loop->stop();
            });
    
          $loop->run();
    
          // Check, that user stayed logged
          $this->assertFalse(self::$closed);
        }
    
        private function createSession($email)
        {
          $client = static::createClient();
          $container = $client->getContainer();
    
          $session = $container->get('session');
          $session->set('logged', true);
    
          $userManager = $container->get('fos_user.user_manager');
          $em = $container->get('doctrine.orm.entity_manager');
          $loginManager = $container->get('fos_user.security.login_manager');
          $firewallName = 'main';
    
          $user = $userManager->findUserByEmail($email);
    
          $loginManager->loginUser($firewallName, $user);
    
          // save the login token into the session and put it in a cookie
          $container->get('session')->set('_security_' . $firewallName,
            serialize($container->get('security.token_storage')->getToken()));
          $container->get('session')->save();
          $client->getCookieJar()->set(new Cookie($session->getName(), $session->getId()));
    
    
          // Create session in database
          $pdo = new PDOSessionStorage();
          $pdo->setSessId($session->getId());
          $pdo->setSessTime(time());
          $pdo->setSessData(serialize($container->get('security.token_storage')->getToken()));
          $pdo->setSessLifetime(1440);
    
          $em->persist($pdo);
          $em->flush();
    
          return $client;
      }
    
    }
    
    作为config_test.yml,我以以下方式配置了会话:

    session:
        storage_id:     session.storage.mock_file
        handler_id:     session.handler.pdo
    
    对于服务器端websocket实现,我使用Ratchet,它由以下Symfony包包装:

    测试WebSocket时如何对用户进行身份验证?在websocket服务器上,用户总是类似于“anon-1546885062556b43b424c94871115670”,但当我手动测试时,他连接正确

    附加问题(次要):如何测试主题订阅?(公开发行) 互联网上没有关于这一点的博客或其他内容

    更新:从来没有人对他们的WebSocket进行过功能测试?这是不重要的、无用的还是为什么没有人能在这个重要的话题上提供帮助?

    这里的情况是本末倒置。在客户端连接上设置cookie时,如果cookie限制(httpOnly、secure、domain、path等)匹配,则cookie仅在后续请求(websockets或XHR、GET、POST等)时发送

    任何可用的cookie都会在websocket连接的初始握手期间发送。在开放连接上设置cookie将在客户端上设置cookie,但由于套接字已经是开放连接并已建立(握手后),服务器将在该连接期间对这些cookie视而不见

    有些人在握手时成功地设置了cookie。但是,这需要服务器和客户端套接字实现支持此行为,并将凭据作为get参数传递(错误做法)

    所以我认为你唯一的选择是:

    • 在打开websocket之前,通过XHR或其他请求处理身份验证
    • 使用websocket进行身份验证,但成功登录后:
      • 设置身份验证cookie
      • 关闭现有的套接字
      • 从客户端启动一个新套接字(该套接字随后将携带您的身份验证cookie)
    • 完全忘记cookies,并根据开放连接的请求/资源ID在服务器上处理身份验证交换

    如果您选择最后一个选项,您仍然可以设置cookie并查找cookie以在重新连接时恢复连接。

    您只是在寻找传递cookie的方法,还是希望立即发送例如sessionId/userId?我已经用我编写的代码更新了问题。问题是,在Ratchet端,用户在测试中保持匿名。也许我把饼干递错了。会话id在cookie中传输。
    'cookie'=>$symfClient->getContainer()->get('session')->getId()$symfClient->getContainer()->get('session')->getId()
    确定这是正确的吗?第一个不是应该是cookie名称吗?@user3746259好吧,我猜不出哪里出了问题,所以,第一步,直接查看ratchet的websocket代码,收到的原始头是什么?它符合你的期望吗…调试应用程序,直到找到源。这可能是一项乏味的任务,但在任务结束时,您通常会知道它失败的原因。@user3746259似乎没有人遇到过这个问题。唯一的解决方案是在那里进行硬核调试,对不起;o)