Pregunta

Estoy tratando de utilizar Socket.IO en Node.js, y estoy tratando de permitir que el servidor para dar una identidad a cada uno de los clientes Socket.IO. Como el código de socket está fuera del alcance del código del servidor HTTP, que no tiene fácil acceso a la información de petición enviados, así que estoy asumiendo que tendrá que ser enviado durante la conexión. ¿Cuál es el mejor modo de

1) obtener la información al servidor acerca de quién se está conectando a través de Socket.IO

2) autenticar quien dice ser (Actualmente estoy usando Express, si eso hace las cosas más fáciles)

¿Fue útil?

Solución

Use Connect-Redis y tienen Redis como el almacenamiento de sesión para todos los usuarios autenticados. Asegúrese de autenticación envía la clave (normalmente req.sessionID) al cliente. Tener la tienda de esta clave cliente en una cookie.

El conector de acoplamiento (o en cualquier momento posterior) ir a buscar esta clave de la cookie y enviarlo de vuelta al servidor. Buscar la información de la sesión en Redis utilizando esta clave. (Claves)

Por ejemplo:

Del lado del servidor (con Redis como almacenamiento de sesión):

req.session.regenerate...
res.send({rediskey: req.sessionID});

lado del cliente:

//store the key in a cookie
SetCookie('rediskey', <%= rediskey %>); //http://msdn.microsoft.com/en-us/library/ms533693(v=vs.85).aspx

//then when socket is connected, fetch the rediskey from the document.cookie and send it back to server
var socket = new io.Socket();

socket.on('connect', function() {
  var rediskey = GetCookie('rediskey'); //http://msdn.microsoft.com/en-us/library/ms533693(v=vs.85).aspx
  socket.send({rediskey: rediskey});
});

lado del servidor:

//in io.on('connection')
io.on('connection', function(client) {
  client.on('message', function(message) {

    if(message.rediskey) {
      //fetch session info from redis
      redisclient.get(message.rediskey, function(e, c) {
        client.user_logged_in = c.username;
      });
    }

  });
});

Otros consejos

También le gusta la forma pusherapp hace canales privados . introducir descripción de la imagen aquí

Se genera una ID única y socket enviados al navegador por medio de empuje. Esto es enviado a su aplicación (1) a través de una solicitud AJAX que autoriza al usuario para acceder al canal en contra de su sistema de autenticación existente. Si Sus declaraciones de éxito de aplicación de una cadena de autorización para el navegador firmado con que secreta empujador. Esto es enviado a empujador sobre el WebSocket, que completa la autorización (2) Si los partidos de cuerda autorización.

Debido a que también tiene socket.io socket_id único para cada toma.

socket.on('connect', function() {
        console.log(socket.transport.sessionid);
});

Se utiliza cadenas de autorización firmadas para autorizar a los usuarios.

todavía no he reflejado esto a socket.io, pero creo que podría ser un concepto bastante interesante.

Sé que esto es poco viejo, pero para los futuros lectores, además del enfoque de análisis de la galleta y la recuperación de la sesión desde el almacenamiento (por ejemplo. passport.socketio ) podría también considerar un enfoque basado en token.

En este ejemplo utilizo web JSON fichas que son bastante estándar. Usted tiene que dar a la página del cliente el testigo, en este ejemplo se imagina un punto final de autenticación que vuelve JWT:

var jwt = require('jsonwebtoken');
// other requires

app.post('/login', function (req, res) {

  // TODO: validate the actual user user
  var profile = {
    first_name: 'John',
    last_name: 'Doe',
    email: 'john@doe.com',
    id: 123
  };

  // we are sending the profile in the token
  var token = jwt.sign(profile, jwtSecret, { expiresInMinutes: 60*5 });

  res.json({token: token});
});

Ahora, el servidor socket.io puede ser configurado de la siguiente manera:

var socketioJwt = require('socketio-jwt');

var sio = socketIo.listen(server);

sio.set('authorization', socketioJwt.authorize({
  secret: jwtSecret,
  handshake: true
}));

sio.sockets
  .on('connection', function (socket) {
     console.log(socket.handshake.decoded_token.email, 'has joined');
     //socket.on('event');
  });

El middleware socket.io-JWT espera que el token en una cadena de consulta, por lo que desde el cliente sólo tiene que adjuntarlo al conectar: ??

var socket = io.connect('', {
  query: 'token=' + token
});

Me escribió una explicación más detallada sobre este método y las galletas aquí.

En este artículo ( http: //simplapi.wordpress.com/2012/04/13/php-and-node-js-session-share-redi/ ) muestra cómo

  • tienda de sesiones HTTP en el servidor Redis (usando Predis)
  • conseguir estas sesiones de Redis en Node.js por el identificador de sesión enviada en una cookie

El uso de este código que es capaz de conseguir en socket.io, también.

var io = require('socket.io').listen(8081);
var cookie = require('cookie');
var redis = require('redis'), client = redis.createClient();
io.sockets.on('connection', function (socket) {
    var cookies = cookie.parse(socket.handshake.headers['cookie']);
    console.log(cookies.PHPSESSID);
    client.get('sessions/' + cookies.PHPSESSID, function(err, reply) {
        console.log(JSON.parse(reply));
    });
});

Aquí está mi intento de tener el siguiente trabajo:

  • expreso : 4,14
  • socket.io : 1,5
  • pasaporte (utilizando sesiones): 0,3
  • Redis : 2,6 (estructura de datos muy rápido para sesiones de mango; pero se puede usar otros como MongoDB demasiado Sin embargo, le animo a utilizar esto para datos de sesión + MongoDB para almacenar otros datos persistentes como. usuarios)

Dado que es posible que desee añadir algunas solicitudes de la API, así, vamos a utilizar también http paquete tenga HTTP y toma Web que trabajan en el mismo puerto.


server.js

El siguiente extracto sólo incluye todo lo necesario para establecer las tecnologías anteriores arriba. Se puede ver la versión completa server.js que utilicé en uno de mis proyectos aquí .

import http from 'http';
import express from 'express';
import passport from 'passport';
import { createClient as createRedisClient } from 'redis';
import connectRedis from 'connect-redis';
import Socketio from 'socket.io';

// Your own socket handler file, it's optional. Explained below.
import socketConnectionHandler from './sockets'; 

// Configuration about your Redis session data structure.
const redisClient = createRedisClient();
const RedisStore = connectRedis(Session);
const dbSession = new RedisStore({
  client: redisClient,
  host: 'localhost',
  port: 27017,
  prefix: 'stackoverflow_',
  disableTTL: true
});

// Let's configure Express to use our Redis storage to handle
// sessions as well. You'll probably want Express to handle your 
// sessions as well and share the same storage as your socket.io 
// does (i.e. for handling AJAX logins).
const session = Session({
  resave: true,
  saveUninitialized: true,
  key: 'SID', // this will be used for the session cookie identifier
  secret: 'secret key',
  store: dbSession
});
app.use(session);

// Let's initialize passport by using their middlewares, which do 
//everything pretty much automatically. (you have to configure login
// / register strategies on your own though (see reference 1)
app.use(passport.initialize());
app.use(passport.session());

// Socket.IO
const io = Socketio(server);
io.use((socket, next) => {
  session(socket.handshake, {}, next);
});
io.on('connection', socketConnectionHandler); 
// socket.io is ready; remember that ^this^ variable is just the 
// name that we gave to our own socket.io handler file (explained 
// just after this).

// Start server. This will start both socket.io and our optional 
// AJAX API in the given port.
const port = 3000; // Move this onto an environment variable, 
                   // it'll look more professional.
server.listen(port);
console.info(`🌐  API listening on port ${port}`);
console.info(`🗲 Socket listening on port ${port}`);

zócalos / index.js

Nuestra socketConnectionHandler, yo simplemente no les gusta poner todo dentro server.js (aunque perfectamente podría), sobre todo porque este archivo puede terminar bastante que contiene una gran cantidad de código con bastante rapidez.

export default function connectionHandler(socket) {
  const userId = socket.handshake.session.passport &&
                 socket.handshake.session.passport.user; 
  // If the user is not logged in, you might find ^this^ 
  // socket.handshake.session.passport variable undefined.

  // Give the user a warm welcome.
  console.info(`⚡︎ New connection: ${userId}`);
  socket.emit('Grettings', `Grettings ${userId}`);

  // Handle disconnection.
  socket.on('disconnect', () => {
    if (process.env.NODE_ENV !== 'production') {
      console.info(`⚡︎ Disconnection: ${userId}`);
    }
  });
}

Material extra (cliente):

Sólo una versión muy básica de lo que podría ser el JavaScript socket.io cliente:

import io from 'socket.io-client';

const socketPath = '/socket.io'; // <- Default path.
                                 // But you could configure your server
                                // to something like /api/socket.io

const socket = io.connect('localhost:3000', { path: socketPath });
socket.on('connect', () => {
  console.info('Connected');
  socket.on('Grettings', (data) => {
    console.info(`Server gretting: ${data}`);
  });
});
socket.on('connect_error', (error) => {
  console.error(`Connection error: ${error}`);
});

Referencias:

Yo simplemente no podía hacer referencia en el código, así que me trasladé aquí.

1: Cómo configurar sus estrategias de pasaporte: https://scotch.io/tutorials/easy-node-authentication-setup-and-local#handling-signupregistration

sesión de uso y Redis entre c / s

// lado del servidor

io.use(function(socket, next) {
 console.log(socket.handshake.headers.cookie); // get here session id and match from redis session data
 next();
});

esto debe hacerlo

//server side

io.sockets.on('connection', function (con) {
  console.log(con.id)
})

//client side

var io = io.connect('http://...')

console.log(io.sessionid)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top