2016-05-31 130 views
34

我试图测试一个场景,一方面,匿名用户应该立即从WebSocket连接断开连接,另一方面,经过身份验证的用户应该停留在websocket连接。第一种情况很容易通过使用下面的代码进行测试。身份验证过程不起作用。PHP Websocket在测试中验证用户(传递会话cookie)

对于会话存储,我将Cookie身份验证与数据库结合使用:Symfony PDO Session Storage。这一切都工作正常,但是当涉及到通过使用身份验证来测试所描述的行为时,我不知道如何在测试中对用户进行身份验证。作为一个客户,我使用Pawl asynchronous Websocket client.这看起来如下:

\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"; 
}); 

我知道,作为第三个参数,我可以通过报头信息“连接”的方法,但我不能找到一种方法,使客户端已连接并且在ws握手期间cookie正确传递。我认为是这样的:

  1. 通过创建authentication token
  2. 我创建的会话表中的数据库与序列化用户
  3. 一个新条目我通过创建的cookie作为第三个参数验证客户端连接方法

这是我认为可以工作的理论,但用户始终在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("[email protected]"); 

     $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实现,我使用的棘轮,其被由以下Symfony包裹包装:Gos Websocket Bundle

如何在测试websockets时验证用户?在websocket服务器上,用户总是像“anon-15468850625756b3b424c94871115670”,但是当我手动测试时,他的连接正确。

其他问题(二级):如何测试订阅主题? (pubsub) 在互联网上没有关于此的博客条目或任何其他内容。

更新:没有人曾经功能测试过他们的websockets?这是不重要的,无用的或为什么任何人都无法帮助那个重要的话题?

+0

你只想找一种方式来传递cookie,或者你想立即发送一个sessionId/userId的例子吗? – mitchken

+0

我已经用我写的代码更新了这个问题。问题是,在棘轮方面,用户在测试中保持匿名。也许我错误地传递了cookie。会话ID在cookie中传输。 – user3746259

+2

''Cookie'=> $ symfClient-> getContainer() - > get('session') - > getId()。 '='。 $ symfClient-> getContainer() - > get('session') - > getId()'确定这是正确的?首先不应该是cookie的名字? – bwoebi

回答

1

你在这里有一个前车的情况。当你在一个客户端连接上设置一个cookie时,这个cookie只能在后续的请求(websockets或者XHR,GET,POST等)上发送,它提供了cookie的限制(httpOnly,secure,domain,path等)匹配。

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

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

因此,我认为你的唯一真正的选择是:通过XHR或其他要求

  • 处理身份验证打开的WebSocket
  • 用于身份验证的WebSocket的,但后来就成功登录:
    • 设置您的授权码
    • 关闭现有插座
    • 从客户端启动一个新的套接字(然后将携带您的身份验证cookie)
  • 忘记cookie并根据打开的连接的请求/资源ID在服务器上处理身份验证交换。

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