我正在尝试测试一种情境,即一方面匿名用户应立即从Websocket连接中断开,另一方面已认证的用户应该保持在Websocket连接中。第一种情况可以使用下面的代码轻松地进行测试。然而,身份验证进程无法工作。
对于会话存储,我正在使用Cookie身份验证与数据库相结合:Symfony PDO Session Storage。它运行良好,但是当涉及到通过身份验证来测试所描述的行为时,我不知道如何在测试中对用户进行身份验证。作为客户端,我正在使用Pawl异步Websocket客户端。 它看起来像这样:
\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”方法,但我找不到一种方法使客户端在连接时正确地传递Cookie。我想到了以下方式:
- 通过创建身份验证令牌对客户端进行身份验证
- 在数据库中创建一个序列化用户的新会话表项
- 将创建的Cookie作为第三个参数传递给连接方法
这是我认为可以起作用的理论,但用户始终保持匿名状态。以下是迄今为止的代码:
// ...
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):
session:
storage_id: session.storage.mock_file
handler_id: session.handler.pdo
对于服务器端的websocket实现,我使用了Ratchet,它被以下Symfony bundle包装:Gos Websocket Bundle
在测试websocket时如何验证用户身份?在websocket服务器上,用户始终是类似于“anon-15468850625756b3b424c94871115670”这样的东西,但是当我手动测试时,他会正确连接。
附加问题(次要):如何测试订阅主题?(发布-订阅)互联网上没有博客文章或其他内容。
更新:难道没有人对他们的websocket进行功能测试吗?这很不重要、无用还是为什么没有人在这个重要的话题上提供帮助?
MessageComponentInterface
接口的类。 - bwoebi