PHP Websocket 在测试中验证用户(通过会话 cookie) [英] PHP Websocket authenticate user in a test (pass session cookie)

查看:63
本文介绍了PHP Websocket 在测试中验证用户(通过会话 cookie)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to test a scenario, that on the one hand, anonymous users should immediately get a disconnect from a Websocket connection and on the other hand, authenticated users should stay in the websocket connection. The first case is easy testable by using the code down under. The authentication process is not working.

对于会话存储,我将 Cookie 身份验证与数据库结合使用:SymfonyPDO 会话存储.一切正常,但是在使用身份验证测试所描述的行为时,我不知道如何在测试中对用户进行身份验证.作为客户端,我使用的是 Pawl 异步 Websocket 客户端. 如下所示:

For session storage, I am using Cookie authentication in combination with a database: Symfony PDO Session Storage. It's all working fine, but when it comes to testing the described behaviour by using authentication, I don't know how to authenticate the user in a test. As a client, I am using Pawl asynchronous Websocket client. This looks the following:

\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 握手期间连接客户端并正确传递 cookie.我想到了类似的东西:

I know that as a third parameter, I can pass header information to the "connect" method, but I cannot find a way so that the client is connected and the cookie is passed correctly during the ws handshake. I thought of something like:

  1. 通过创建身份验证令牌
  2. 对客户端进行身份验证
  3. 我使用序列化用户在数据库的会话表中创建了一个新条目
  4. 我将创建的 cookie 作为第三个参数传递给 connect 方法

这是我认为可行的理论,但用户总是在 websocket 端保持匿名.到目前为止,这里是理论的代码:

This is the theory I thought that would work, but the user always stays anonym on websocket side. Here the code to the theory so far:

// ...
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,我按以下方式配置会话:

As config_test.yml, I configured the session the following way:

session:
    storage_id:     session.storage.mock_file
    handler_id:     session.handler.pdo

对于服务器端 websocket 实现,我使用 Ratchet,它被以下 Symfony 包包裹:Gos Websocket Bundle

For server side websocket implementation, I am using Ratchet, which is being wrapped by the following Symfony bundle: Gos Websocket Bundle

在测试 websockets 时如何验证用户?在 websocket 服务器上,用户总是类似于anon-15468850625756b3b424c94871115670",但是当我手动测试时,他连接正确.

How to authenticate the user when testing websockets? On websocket server, the user is always something like "anon-15468850625756b3b424c94871115670", but when I test manually, he gets connected correct.

附加问题(次要问题):如何测试订阅主题?(发布订阅)互联网上没有博客条目或其他任何关于此的内容.

Additional question (secondary): How to test the subscription to topics? (pubsub) There are no blog entries or anything else about this on the internet.

更新:没有人测试过他们的 websockets 吗?这是不重要的、没用的,还是为什么没有人能在这个重要的话题上提供帮助?

Update: No one ever functional tested their websockets? Is this unimportant, useless or why can't anyone help on that important topic?

推荐答案

这里有手推车的情况.当您在客户端连接上设置 cookie 时,如果 cookie 限制(httpOnly、安全、域、路径等),则该 cookie 仅在后续请求(websockets 或 XHR、GET、POST 等)上发送) 匹配.

You have a cart before the horse situation here. When you set a cookie on a client connection that cookie is then only sent on subsequent requests (websockets or XHR, GET, POST, etc) provided the cookie restrictions (httpOnly, secure, domain, path, etc) match.

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

Any cookies available are sent during the initial handshake of the websocket connection. Setting a cookie on an open connection will set the cookie on the client but since the socket is already an open connection and established (post handshake) the server will be blind to those cookies for the duration of that connection.

有些人在握手期间成功设置了 cookie.但是,这需要服务器和客户端套接字实现支持此行为并将凭据作为获取参数传递(不好的做法).

Some people have had success setting the cookie during the handshake. However, that requires the server and client socket implementations supporting this behavior and passing credentials as get parameters (bad practice).

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

So I think your only real options are:

  • 通过 XHR 或其他请求在打开 websocket 之前处理身份验证
  • 使用 websocket 进行身份验证,但在成功登录后:
    • 设置您的身份验证 cookie
    • 关闭现有套接字
    • 从客户端启动一个新的套接字(然后将携带您的身份验证 cookie)

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

    If you choose the last option you could still set the cookie and look for the cookie to restore connections on reconnects.

    这篇关于PHP Websocket 在测试中验证用户(通过会话 cookie)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆