Question

Je suis en train d'utiliser Socket.IO dans Node.js, et essaie de permettre au serveur de donner une identité à chacun des clients Socket.IO. Comme le code socket est en dehors du champ d'application du code du serveur http, il n'a pas accès facile à l'information demande écrite adressée, donc je suppose qu'il devra être envoyé pendant la connexion. Quelle est la meilleure façon de

1) obtenir les informations au serveur sur qui se connecte via Socket.IO

2) Authentifier qui ils disent qu'ils sont (je suis actuellement en utilisant Express, si cela rend les choses plus facile)

Était-ce utile?

La solution

Utiliser Connect-Redis et ont Redis que votre magasin de session pour tous les utilisateurs authentifiés. Assurez-vous que l'authentification vous envoyez la clé (normalement req.sessionID) au client. Avoir la boutique client cette clé dans un cookie.

Sur la prise de connexion (ou à tout moment plus tard) chercher cette clé à partir du cookie et l'envoyer au serveur. Fetch les informations de session à l'aide de cette clé Redis. (Touche GET)

Par exemple:

côté serveur (avec Redis comme magasin de session):

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

Côté 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});
});

côté serveur:

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

  });
});

Autres conseils

J'ai aussi aimé la façon dont pusherapp fait chaînes privées .

  

A id prise unique est généré et   envoyé au navigateur par Pusher. C'est   envoyé à votre application (1) par l'intermédiaire d'un   demande AJAX qui autorise l'utilisateur   pour accéder au canal contre votre   système d'authentification existant. Si   retours avec succès de votre application une   chaîne d'autorisation au navigateur   signé avec vous un secret Pusher. C'est   envoyé à Pusher sur le WebSocket,   qui vient compléter l'autorisation (2)   si les matchs de chaîne d'autorisation.

Parce que aussi socket.io a socket_id unique pour chaque prise.

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

Ils ont utilisé chaînes d'autorisation signée pour autoriser les utilisateurs.

Je ne l'ai pas encore à ce miroir socket.io, mais je pense que ce pourrait être concept assez intéressant.

Je sais que c'est un peu vieux, mais pour les futurs lecteurs, en plus de l'approche de l'analyse syntaxique cookie et la récupération de la session du stockage (par exemple. passport.socketio ) vous pouvez également envisager une approche basée sur des jetons.

Dans cet exemple, j'utilise JSON Tokens Web qui sont assez standard. Il faut donner à la page client le jeton, dans cet exemple imaginer un point final d'authentification que les rendements 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});
});

Maintenant, votre serveur socket.io peut être configuré comme suit:

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

Le middleware socket.io-JWT attend le jeton dans une chaîne de requête, donc du client vous suffit de le fixer lors de la connexion:

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

J'ai écrit une explication plus détaillée sur cette méthode et les cookies .

Cet article ( http: //simplapi.wordpress.com/2012/04/13/php-and-node-js-session-share-redi/ ) montre comment

  • sessions de magasin du serveur HTTP dans Redis (en utilisant Predis)
  • obtenir ces sessions de Redis à Node.js par l'identifiant de session envoyé dans un cookie

En utilisant ce code, vous pouvez les obtenir dans socket.io aussi.

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

Voici ma tentative d'avoir le travail suivant:

  • express : 4,14
  • socket.io : 1.5
  • passeport (en utilisant des sessions): 0,3
  • Redis : 2.6 (structure de données vraiment rapide à des séances de poignée, mais vous pouvez utiliser d'autres comme MongoDB aussi Cependant, je vous encourage à utiliser les données de session + MongoDB pour stocker d'autres données persistantes comme. utilisateurs)

Puisque vous pouvez ajouter des requêtes API ainsi, nous allons également utiliser http package pour avoir HTTP et socket Web travaillant dans le même port.


server.js

L'extrait suivant ne comprend que tout ce que vous devez définir les technologies précédentes vers le haut. Vous pouvez voir la version complète de server.js que j'utilisé dans l'un de mes projets .

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

prises / index.js

Notre socketConnectionHandler, je ne aime pas mettre tout à l'intérieur server.js (même si vous parfaitement possible), d'autant plus que ce fichier peut finir par contenir tout à fait beaucoup de code assez rapidement.

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

matériel supplémentaire (client):

Juste une version très basique de ce que le client du JavaScript pourrait être:

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

Références:

Je ne pouvait pas faire référence à l'intérieur du code, donc je me suis déplacé ici.

1: Comment mettre en place vos stratégies Passeport: https://scotch.io/tutorials/easy-node-authentication-setup-and-local#handling-signupregistration

session d'utilisation et Redis entre c / s

// côté serveur

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

cela devrait le faire

//server side

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

//client side

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

console.log(io.sessionid)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top