Аутентификация Socket.IO

Я пытаюсь использовать Socket.IO в Node.js и пытаюсь разрешить серверу предоставлять идентификатор каждому из клиентов Socket.IO. Поскольку код сокета выходит за пределы кода http-сервера, он не имеет легкого доступа к отправляемой информации о запросе, поэтому я предполагаю, что его нужно будет отправить во время соединения. Каков наилучший способ

1) получить информацию на сервере о том, кто подключается через Socket.IO

2) аутентифицировать тех, кого они говорят (я в настоящее время пользуюсь Express, если это упрощает)

Используйте connect-redis и переустановите в качестве хранилища сеансов для всех пользователей, прошедших проверку подлинности. Убедитесь, что при аутентификации вы отправляете ключ (обычно req.sessionID) клиенту. Попросите клиента сохранить этот ключ в файле cookie.

Включение сокета (или в любое время позже) извлеките этот ключ из файла cookie и отправьте его обратно на сервер. Извлеките информацию о сеансе в redis с помощью этого ключа. (Ключ GET)

Например:

Серверная сторона (с redis как хранилище сеансов):

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

Сторона клиента:

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

Серверная сторона:

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

Мне также понравилось, как pusherapp делает частные каналы . введите описание изображения здесь

Уникальный идентификатор сокета генерируется и отправляется в браузер Pusher. Это отправляется в ваше приложение (1) через запрос AJAX, который разрешает пользователю получать доступ к каналу против существующей системы аутентификации. В случае успеха ваше приложение вернет строку авторизации в браузер, подписанный с вами в тайне Pusher. Это отправляется Pusher через WebSocket, который завершает авторизацию (2), если строка авторизации соответствует.

Потому что также socket.io имеет уникальный socket_id для каждого сокета.

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

Они использовали подписанные строки авторизации для авторизации пользователей.

Я еще не отразил это на socket.io , но я думаю, что это может быть довольно интересная концепция.

Я знаю, что это немного устарело, но для будущих читателей в дополнение к подходу к анализу cookie и извлечению сеанса из хранилища (например, паспорт.socketio ) вы также можете рассмотреть подход, основанный на токенах.

В этом примере я использую JSON Web Tokens, которые довольно стандартны. Вы должны указать на клиентскую страницу токен, в этом примере представьте конечную точку аутентификации, которая возвращает 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}); }); 

Теперь ваш сервер socket.io можно настроить следующим образом:

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

Средство промежуточного слоя socket.io-jwt ожидает маркер в строке запроса, поэтому от клиента вам нужно будет только подключить его при подключении:

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

Я написал более подробное объяснение этого метода и файлов cookie здесь .

В этой статье ( http://simplapi.wordpress.com/2012/04/13/php-and-node-js-session-share-redi/ ) показано, как

  • хранить сеансы HTTP-сервера в Redis (используя Predis)
  • получить эти сеансы из Redis в node.js идентификатором сеанса, отправленным в файл cookie

Используя этот код, вы также можете получить их в socket.io.

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

Вот моя попытка работать следующим образом:

  • express : 4.14
  • socket.io : 1.5
  • паспорт (с использованием сеансов): 0,3
  • redis : 2.6 (действительно быстрая структура данных для обработки сеансов, но вы можете использовать других, таких как MongoDB. Однако я рекомендую вам использовать это для данных сеанса + MongoDB для хранения других постоянных данных, таких как Пользователи)

Так как вы можете добавить некоторые запросы API, мы также будем использовать http- пакет, чтобы иметь как HTTP, так и Web-сокеты, работающие в одном и том же порту.


server.js

Следующий отрывок содержит только все, что нужно для установки предыдущих технологий. Вы можете увидеть полную версию server.js, которую я использовал в одном из моих проектов здесь .

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

розетки / index.js

Наш socketConnectionHandler , мне просто не нравится помещать все в server.js (даже если вы отлично это сделали), тем более, что этот файл может в конечном итоге содержать довольно много кода довольно быстро.

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

Дополнительный материал (клиент):

Просто очень простая версия того, чем может быть клиент JavaScript socket.io:

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

Рекомендации:

Я просто не мог ссылаться внутри кода, поэтому я переместил его сюда.

1: Как настроить страtagsи паспорта: https://scotch.io/tutorials/easy-node-authentication-setup-and-local#handling-signupregistration

использовать сеанс и перерисовать между c / s

// серверная сторона

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

это должно это сделать

 //server side io.sockets.on('connection', function (con) { console.log(con.id) }) //client side var io = io.connect('http://...') console.log(io.sessionid) 
  • Может ли какой-то хакер украсть файл cookie у пользователя и войти с этим именем на веб-сайт?
  • Аутентификация RESTful
  • Как защитить статические файлы с помощью аутентификации формы ASP.NET в IIS 7.5?
  • Авторизация Google OAuth 2 - Ошибка: redirect_uri_mismatch
  • Как выйти из веб-сайта с использованием аутентификации BASIC?
  • Безопасное шифрование https для приложения iPhone на веб-странице
  • HttpURLConnection отлично работает в Android 2.x, но НЕ в 4.1: не обнаружены проблемы аутентификации
  • Настройка Spring Security 3.x для создания нескольких точек входа
  • Микширование форм с помощью проверки подлинности Windows
  • OWIN - Authentication.SignOut (), похоже, не удаляет файл cookie
  • Проверка подлинности браузера с использованием Selenium
  • Interesting Posts

    Число регулярных выражений от 1 до 100

    Начальная емкость ArrayList и IndexOutOfBoundsException

    Передача аргументов в osascript через функцию оболочки в OS X Mountain Lion

    Как сделать снимок экрана текущей веб-страницы с помощью javascript / jquery

    Как я могу запускать Firefox без панели вкладок, без верхней панели, без адресной строки и не растягиваться до полноэкранного размера?

    Использование инициализаторов и конструкторов в Java

    Могу ли я расширить панель задач на нескольких мониторах в Windows 8?

    Экспорт в Excel в Asp.net MVC

    Прочитать файл по строкам в обратном порядке

    Как выполнять команды в другой папке, не повторяя путь к папке?

    Каковы нормальные формы базы данных и вы можете привести примеры?

    Android добавляет подменю в menuItem, где есть addSubMenu ()?

    Список групп Java 8 lambdas на карте

    Указание формулы в R с glm без явного объявления каждого ковариата

    Как проверить, является ли бинарный файл 32 или 64 бит в Windows?

    Давайте будем гением компьютера.