Socket.IO Uwierzytelnianie

Próbuję użyć Socket.IO w węźle.js, i staram się umożliwić serwerowi nadanie tożsamości każdemu z Socket.IO klientów. Ponieważ kod gniazda jest poza zakresem kodu serwera http, nie ma łatwego dostępu do wysyłanych informacji o żądaniu, więc zakładam, że będzie musiał zostać wysłany podczas połączenia. Jaki jest najlepszy sposób na

1) Uzyskaj informację na serwerze o tym, kto łączy się za pośrednictwem Socket.IO

2) uwierzytelnić, kim mówią, że są (Jestem obecnie używam Express, jeśli to ułatwia sprawę)

Author: Ryan, 2011-01-21

7 answers

Użyj connect-redis i miej redis jako magazyn sesji dla wszystkich uwierzytelnionych użytkowników. Upewnij się, że przy uwierzytelnianiu wysyłasz klucz (normalnie req.sessionID) do klienta. Niech klient zapisze ten klucz w pliku cookie.

Na socket connect (lub w dowolnym momencie później) Pobierz ten klucz z pliku cookie i wyślij go z powrotem na serwer. Pobierz informacje o sesji w redis za pomocą tego klucza. (GET key)

Eg:

Strona serwera (z redis jako magazyn sesji):

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

Klient Strona:

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

Strona serwera:

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

  });
});
 99
Author: Shripad Krishna,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-27 08:37:55

Podobało mi się również sposób pusherapp robi prywatne kanały.Tutaj wpisz opis obrazka

Generowany jest unikalny identyfikator gniazda i wysyłane do przeglądarki przez popychacz. To jest wysłane na twoje zgłoszenie (1) za pośrednictwem Żądanie AJAX autoryzujące użytkownika aby uzyskać dostęp do kanału przed istniejący system uwierzytelniania. Jeśli pomyślnie Twoja aplikacja zwraca ciąg autoryzacji do przeglądarki podpisałem z Tobą sekret popychacza. To jest wysłane do Pusher przez WebSocket, który kończy autoryzację (2) jeśli łańcuch autoryzacji się zgadza.

Ponieważ również socket.io ma unikalny identyfikator socket_id dla każdego gniazda.

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

Użyli podpisanych łańcuchów autoryzacyjnych do autoryzacji użytkowników.

Jeszcze tego nie odtworzyłem socket.io, ale myślę, że to może być całkiem interesująca koncepcja.

 30
Author: Alfred,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-24 14:11:12

Wiem, że to trochę stare, ale dla przyszłych czytelników oprócz podejścia do parsowania plików cookie i pobierania sesji z magazynu(np. Paszport.socketio ) można również rozważyć podejście oparte na tokenie.

W tym przykładzie używam tokenów JSON Web, które są dość standardowe. W tym przykładzie wyobraź sobie punkt końcowy uwierzytelniania, który zwraca 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: '[email protected]',
    id: 123
  };

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

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

Teraz, twój socket.io serwer można skonfigurować jako "follows": {]}

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');
  });
[[3]}oprogramowanie pośredniczące socket.io-jwt oczekuje tokena w łańcuchu zapytań, więc od klienta musisz go tylko dołączyć podczas łączenia:
var socket = io.connect('', {
  query: 'token=' + token
});

Bardziej szczegółowe wyjaśnienie tej metody i plików cookie napisałem tutaj .

 20
Author: José F. Romaniello,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-16 15:01:17

Ten artykuł ( http://simplapi.wordpress.com/2012/04/13/php-and-node-js-session-share-redi / ) pokazuje jak

  • przechowuj sesje serwera HTTP w Redis (używając Predis)
  • pobierz te sesje z Redis w node.js przez identyfikator sesji wysłany w pliku cookie

Używając tego kodu możesz je w socket.io też.

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));
    });
});
 2
Author: Blade1336,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-25 17:30:22

Oto moja próba wykonania:

  • express: 4.14
  • socket.io: 1.5
  • passport (using sessions): 0.3
  • redis : 2.6 (naprawdę szybka struktura danych do obsługi sesji; ale możesz również użyć innych, takich jak MongoDB. Jednak zachęcam do korzystania z tego dla danych sesji + MongoDB do przechowywania innych trwałych danych, takich jak użytkownicy)

Ponieważ możesz również chcieć dodać kilka żądań API, będziemy użyj również pakietu http, aby oba gniazda HTTP i Web działały w tym samym porcie.


Serwer.js

Poniższy wyciąg zawiera tylko wszystko, czego potrzebujesz, aby skonfigurować poprzednie technologie. Możesz zobaczyć cały serwer.wersja js, której użyłem w jednym z moich projektów tutaj .

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

Gniazda / indeks.js

Nasz socketConnectionHandler, po prostu nie lubię umieszczać wszystkiego wewnątrz serwera.js (mimo, że można), tym bardziej, że ten plik może skończyć się dość szybko zawierając sporo kodu.

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

Dodatkowy materiał (klient):

Tylko bardzo podstawowa wersja tego, co JavaScript socket.io klient może być:

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

Bibliografia:

po prostu nie mogłem odwołać się do kodu, więc przeniosłem go tutaj.

1: Jak skonfigurować strategie paszportowe: https://scotch.io/tutorials/easy-node-authentication-setup-and-local#handling-signupregistration
 2
Author: zurfyx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-15 19:30:54

Użyj sesji i redis pomiędzy c / S

// strona serwera

io.use(function(socket, next) {
 console.log(socket.handshake.headers.cookie); // get here session id and match from redis session data
 next();
});
 0
Author: onplanner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-18 15:06:57

This should do it

//server side

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

//client side

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

console.log(io.sessionid)
 -3
Author: dominic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-05 12:29:45