tutorial - websocket php y html5
Usuario de autentificación de PHP Websocket en una prueba(cookie de sesión de pase) (1)
Estoy intentando probar un escenario, que por un lado, los usuarios anónimos deberían desconectarse inmediatamente de una conexión Websocket y, por otro lado, los usuarios autenticados deberían permanecer en la conexión del websocket. El primer caso es fácil de probar utilizando el código de abajo. El proceso de autenticación no está funcionando.
Para el almacenamiento de la sesión, estoy usando la autenticación de Cookie en combinación con una base de datos: Symfony PDO Session Storage . Todo está funcionando bien, pero cuando se trata de probar el comportamiento descrito mediante el uso de autenticación, no sé cómo autenticar al usuario en una prueba. Como cliente, estoy usando Pawl asynchronous Websocket client. Esto se ve de la siguiente manera:
/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";
});
Sé que como tercer parámetro, puedo pasar la información del encabezado al método de "conexión", pero no puedo encontrar la manera para que el cliente esté conectado y la cookie se pase correctamente durante el intercambio de información de ws. Pensé en algo como:
- Autentica un cliente creando un token de autenticación
- Creo una nueva entrada en la tabla de sesión en la base de datos con usuario serializado
- Paso la cookie creada como tercer argumento para el método connect
Esta es la teoría que pensé que funcionaría, pero el usuario siempre se mantiene anónimo en el lado del websocket. Aquí el código de la teoría hasta ahora:
// ...
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;
}
}
Como config_test.yml, configuré la sesión de la siguiente manera:
session:
storage_id: session.storage.mock_file
handler_id: session.handler.pdo
Para la implementación de websocket del lado del servidor, estoy usando Ratchet, que está siendo envuelto por el siguiente paquete de Symfony: Gos Websocket Bundle
¿Cómo autenticar al usuario al probar websockets? En el servidor websocket, el usuario siempre es algo así como "anon-15468850625756b3b424c94871115670", pero cuando lo pruebo manualmente, se conecta correctamente.
Pregunta adicional (secundaria): ¿Cómo probar la suscripción a los temas? (pubsub) No hay entradas de blog ni nada sobre esto en Internet.
Actualización: ¿Nadie ha probado alguna vez sus websockets? ¿Es esto poco importante, inútil o por qué nadie puede ayudar con ese importante tema?
Tienes un carrito antes de la situación del caballo aquí. Cuando configura una cookie en una conexión de cliente, esa cookie solo se envía en solicitudes posteriores (websockets o XHR, GET, POST, etc.) siempre que coincidan las restricciones de cookies (httpOnly, secure, domain, path, etc).
Las cookies disponibles se envían durante el inicio de la conexión websocket. Al establecer una cookie en una conexión abierta se configurará la cookie en el cliente, pero como el socket ya es una conexión abierta y está establecido (post-handshake), el servidor permanecerá ciego a esas cookies mientras dure esa conexión.
Algunas personas han tenido éxito configurando la cookie durante el apretón de manos. Sin embargo, eso requiere que las implementaciones de socket de servidor y cliente admitan este comportamiento y pasen las credenciales como parámetros de obtención (mala práctica).
Así que creo que tus únicas opciones reales son:
- manejar la autenticación a través de XHR u otra solicitud antes de abrir un websocket
- utilice el websocket para la autenticación, pero luego en el inicio de sesión exitoso:
- configura tu cookie de autenticación
- cerrar el zócalo existente
- iniciar un nuevo socket del cliente (que luego llevará su cookie de autenticación)
- Olvide las cookies por completo y gestione un intercambio de autenticación en el servidor en función de la solicitud / ID del recurso para la conexión abierta.
Si elige la última opción, aún puede configurar la cookie y buscar la cookie para restablecer las conexiones al reconectarse.