2016-05-31 48 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以恢復重新連接上的連接。