Files

155 lines
5.3 KiB
Markdown

---
id: 589fc831f9fc0f352b528e77
title: Autenticación con Socket.IO
challengeType: 2
forumTopicId: 301548
dashedName: authentication-with-socket-io
---
# --description--
Actualmente, no puedes determinar quién está conectado a tu web socket. Mientras que `req.user` contiene el objeto user, eso es sólo cuando tu usuario interactúa con el servidor web, y con los web sockets no tienes la `req` (petición) y por lo tanto no hay datos del usuario. Una forma de resolver el problema de saber quién está conectado a tu socket web es analizando (parsing) y decodificando la cookie que contiene la sesión del pasaporte y luego deserializándola para obtener el objeto user. Por suerte, ¡hay un paquete en NPM sólo para esto que convierte una tarea antes compleja en algo sencillo!
Agrega `passport.socketio@~3.7.0`, `connect-mongo@~3.2.0`y `cookie-parser@~1.4.5` como dependencias y requiérelas como `passportSocketIo`, `MongoStore`y `cookieParser` respectivamente. Además, necesitamos inicializar un nuevo almacén de memoria, a partir de `express-session` que requerimos previamente. Debe verse así:
```js
const MongoStore = require('connect-mongo')(session);
const URI = process.env.MONGO_URI;
const store = new MongoStore({ url: URI });
```
Ahora sólo tenemos que decirle a Socket.IO que lo utilice y establezca las opciones. Asegúrate de que esto se agrega antes del código de socket existente y no en el oyente de conexión existente. Para tu servidor, debe verse así:
```js
io.use(
passportSocketIo.authorize({
cookieParser: cookieParser,
key: 'express.sid',
secret: process.env.SESSION_SECRET,
store: store,
success: onAuthorizeSuccess,
fail: onAuthorizeFail
})
);
```
Ten en cuenta que configurar la autenticación de Passport para Socket.IO es muy similar a la forma en que configuramos el middleware de `session` para la API. Esto se debe a que deben usar el mismo método de autenticación: obtener el session id de una cookie y validarlo.
Anteriormente, cuando configuramos el middleware de `session`, no establecíamos explícitamente el nombre de la cookie para la sesión (`key`). Esto se debe a que el paquete `session` estaba usando el valor predeterminado. Ahora que hemos añadido otro paquete que necesita acceso al mismo valor desde las cookies, necesitamos establecer explícitamente el valor `key` en ambos objetos de configuración.
Asegúrate de añadir la `key` con el nombre de la cookie al middleware `session` que coincida con la clave Socket.IO. Además, añade la referencia `store` a las opciones, cerca de donde establecemos `saveUninitialized: true`. Esto es necesario para decirle a Socket.IO con qué sesión relacionarse.
<hr />
Ahora, define las funciones callback de `success` y `fail`:
```js
function onAuthorizeSuccess(data, accept) {
console.log('successful connection to socket.io');
accept(null, true);
}
function onAuthorizeFail(data, message, error, accept) {
if (error) throw new Error(message);
console.log('failed connection to socket.io:', message);
accept(null, false);
}
```
El objeto user ahora es accesible en su objeto socket como `socket.request.user`. Por ejemplo, ahora puedes añadir lo siguiente:
```js
console.log('user ' + socket.request.user.name + ' connected');
```
¡Se registrará en la consola del servidor quién se ha conectado!
Envía tu página cuando creas que lo has hecho bien. Si te encuentras con errores, puedes revisar el proyecto completado hasta este punto [aquí](https://gist.github.com/camperbot/1414cc9433044e306dd7fd0caa1c6254).
# --hints--
`passport.socketio` debe ser una dependencia.
```js
(getUserInput) =>
$.get(getUserInput('url') + '/_api/package.json').then(
(data) => {
var packJson = JSON.parse(data);
assert.property(
packJson.dependencies,
'passport.socketio',
'Your project should list "passport.socketio" as a dependency'
);
},
(xhr) => {
throw new Error(xhr.statusText);
}
);
```
`cookie-parser` debe ser una dependencia.
```js
(getUserInput) =>
$.get(getUserInput('url') + '/_api/package.json').then(
(data) => {
var packJson = JSON.parse(data);
assert.property(
packJson.dependencies,
'cookie-parser',
'Your project should list "cookie-parser" as a dependency'
);
},
(xhr) => {
throw new Error(xhr.statusText);
}
);
```
passportSocketIo debe ser requerido correctamente.
```js
(getUserInput) =>
$.get(getUserInput('url') + '/_api/server.js').then(
(data) => {
assert.match(
data,
/require\((['"])passport\.socketio\1\)/gi,
'You should correctly require and instantiate "passport.socketio"'
);
},
(xhr) => {
throw new Error(xhr.statusText);
}
);
```
passportSocketIo debe estar configurado correctamente.
```js
(getUserInput) =>
$.get(getUserInput('url') + '/_api/server.js').then(
(data) => {
assert.match(
data,
/io\.use\(\s*\w+\.authorize\(/,
'You should register "passport.socketio" as socket.io middleware and provide it correct options'
);
},
(xhr) => {
throw new Error(xhr.statusText);
}
);
```
# --solutions--
```js
/**
Backend challenges don't need solutions,
because they would need to be tested against a full working project.
Please check our contributing guidelines to learn more.
*/
```