Domanda

Sto cercando di utilizzare Socket.IO in Node.js, e sto cercando di consentire al server di dare un'identità a ciascuno dei clienti Socket.IO. Come il codice socket è al di fuori del campo di applicazione del codice del server http, non hanno facile accesso alle informazioni richiesta inviata, quindi sto supponendo che dovrà essere inviato durante la connessione. Qual è il modo migliore per

1) ottenere le informazioni al server su chi sta collegando tramite Socket.IO

2) l'autenticazione che dicono di essere (Attualmente sto usando espresso, se questo fa le cose più facili)

È stato utile?

Soluzione

utilizzano Connect-Redis e hanno Redis come il vostro negozio di sessione per tutti gli utenti autenticati. Assicurati di autenticazione si invia la chiave (normalmente req.sessionID) al client. Avere il client negozio di questa chiave in un cookie.

On presa di connessione (o in qualsiasi momento successivo) prendere questa chiave dal cookie e inviarlo al server. Fetch le informazioni di sessione in Redis utilizzando questa chiave. (Tasto GET)

Esempio:

Lato server (con Redis come file di sessione):

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

lato client:

//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});
});

Lato server:

//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;
      });
    }

  });
});

Altri suggerimenti

Mi è piaciuto anche il modo in cui pusherapp fa canali privati ??. entrare descrizione dell'immagine qui

Un unico presa id viene generato e inviato al browser Pusher. Questo è inviato alla vostra applicazione (1) tramite un richiesta AJAX che autorizza l'utente per accedere al canale contro la vostra sistema di autenticazione esistente. Se successo la vostra applicazione restituisce un stringa di autorizzazione al browser firmato con te Pusher segreto. Questo è inviato a Pusher sopra il WebSocket, che completa l 'autorizzazione (2) se le partite di stringa di autorizzazione.

A causa anche socket.io ha socket_id unico per ogni socket.

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

stringhe autorizzazione firmata per autorizzare gli utenti.

Non ho ancora rispecchiato questo socket.io, ma penso che potrebbe essere piuttosto interessante concetto.

So che questo è po 'vecchio, ma per i futuri lettori in aggiunta all'approccio di analisi dei cookie e recuperare la sessione dal deposito (ad es. passport.socketio ) si potrebbe anche prendere in considerazione un approccio basato su token.

In questo esempio io uso JSON Web Gettoni che sono abbastanza standard. Devi dare alla pagina client il token, in questo esempio immaginate un endpoint di autenticazione che restituisce 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});
});

Ora, il server socket.io può essere configurato come segue:

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');
  });

Il middleware socket.io-JWT si aspetta il token in una stringa di query, quindi dal client è sufficiente attaccarlo quando si collega:

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

ho scritto una spiegazione più dettagliata su questo metodo e biscotti qui .

In questo articolo ( http: //simplapi.wordpress.com/2012/04/13/php-and-node-js-session-share-redi/ ) mostra come

  • memorizzare le sessioni del server HTTP in Redis (usando Predis)
  • ottenere queste sessioni da Redis in node.js dalla id di sessione inviato in un cookie

Con questo codice è in grado di ottenere in socket.io, anche.

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));
    });
});

Ecco il mio tentativo di avere il seguente lavoro:

  • espressa : 4.14
  • socket.io : 1.5
  • passaporto (utilizzando sessioni): 0.3
  • Redis : 2.6 (struttura di dati veramente veloce per le sessioni di manico, ma è possibile utilizzare altri come MongoDB troppo Tuttavia, vi incoraggio a usare questo per i dati di sessione + MongoDB per memorizzare altri dati persistenti come. utenti)

Dal momento che si potrebbe desiderare di aggiungere alcune richieste API così, ci sarà anche utilizzare http pacchetto di avere sia HTTP e presa Web a lavorare nello stesso porto.


server.js

Il seguente estratto include solo tutto il necessario per impostare le tecnologie precedenti in su. È possibile visualizzare la versione completa server.js che ho usato in uno dei miei progetti qui .

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}`);

prese / index.js

Il nostro socketConnectionHandler, io proprio non mi piace mettere tutto dentro server.js (anche se è perfettamente possibile), tanto più che questo file può finire che contiene un bel po 'di codice abbastanza rapidamente.

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}`);
    }
  });
}

materiale extra (client):

solo una versione molto di base di ciò che il JavaScript socket.io client potrebbe essere:

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}`);
});

References:

Ho appena non poteva fare riferimento all'interno del codice, così mi sono trasferito qui.

1: Come impostare le strategie di Passport: https://scotch.io/tutorials/easy-node-authentication-setup-and-local#handling-signupregistration

sessione di utilizzo e Redis tra c / s

// lato server

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

questo dovrebbe farlo

//server side

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

//client side

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

console.log(io.sessionid)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top