socket.io и сеанс?

96

Я использую экспресс-фреймворк. Я хочу получить данные сеанса из socket.io. Я пробовал выразить dynamicHelpers с данными client.listener.server.dynamicViewHelpers, но не могу получить данные сеанса. Есть простой способ сделать это? Пожалуйста, посмотрите код

app.listen(3000);

var io = require('socket.io');
var io = io.listen(app);

io.on('connection', function(client){
    // I want to use session data here
    client.on('message', function(message){
        // or here
    });
    client.on('disconnect', function(){
        // or here
    }); 
});
SFS
источник
5
Или можете использовать этот ОЧЕНЬ КРАСИВЫЙ
Фабиано Сориани
3
@FabianoPS - больше не будет работать - connect больше не предоставляет метод parseCookie, на который он полагается.
UpTheCreek 01
1
@UpTheCreek - Поскольку connect больше не использует метод parseCookie, как это возможно?
Aust
@Aust - Хороший вопрос, я не знаю, какой сейчас лучший подход. Это действительно беспорядок, ИМО. К сожалению, большинство обсуждений обходных путей также сосредоточено на socket.io (не все используют socket.io!). Сейчас есть функция parseSignedCookie, но она тоже закрытая, поэтому есть риск нарушения изменений.
UpTheCreek,
2
Для более новых версий Socket.IO (1.x) и Express (4.x) проверьте этот вопрос SO: stackoverflow.com/questions/25532692/…
pootzko

Ответы:

68

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

Чтобы заставить его работать, на стороне экспресс / подключения я явно определяю хранилище сеансов, поэтому я могу использовать его внутри сокета:

MemoryStore = require('connect/middleware/session/memory'),
var session_store = new MemoryStore();
app.configure(function () {
  app.use(express.session({ store: session_store }));
});

Затем в свой код сокета я включаю структуру подключения, чтобы я мог использовать ее синтаксический анализ файлов cookie для получения connect.sid из файлов cookie. Затем я ищу сеанс в хранилище сеансов, в котором есть этот connect.sid, например:

var connect = require('connect');
io.on('connection', function(socket_client) {
  var cookie_string = socket_client.request.headers.cookie;
  var parsed_cookies = connect.utils.parseCookie(cookie_string);
  var connect_sid = parsed_cookies['connect.sid'];
  if (connect_sid) {
    session_store.get(connect_sid, function (error, session) {
      //HOORAY NOW YOU'VE GOT THE SESSION OBJECT!!!!
    });
  }
});

Затем вы можете использовать сеанс по мере необходимости.

pr0zac
источник
3
Похоже, что socket_client.request был удален в последних версиях socket.io-node
Art
6
Остерегайтесь ... теперь есть новые соглашения для этого ... Я бы предложил вместо этого использовать аутентификацию Socket.IO. См. Сообщение @Jeffer
BMiner
2
К сожалению, это больше не работает - parseCookie больше не является частью утилит подключения. Очевидно, это никогда не было частью общедоступного API. Есть беспорядочная альтернатива - parseSignedCookie, но она тоже приватная, так что я думаю, она тоже рискует исчезнуть ..
UpTheCreek 01
Теперь, когда я думаю об этом ... почему бы просто не установить хранилище для файлов cookie и хранилище для сокета в одно и то же хранилище?
Джеймс
34

Решение модуля Socket.IO-sessions подвергает приложение XSS-атакам, раскрывая идентификатор сеанса на уровне клиента (сценария).

Вместо этого проверьте это решение (для Socket.IO> = v0.7). См. Документы здесь .

Джеффер
источник
1
@Jeffer - это второе решение больше не будет работать с текущей версией connect.
UpTheCreek 01
2
-1 socket.io- это то, что выставляет идентификатор сеанса, а не этот модуль. Это не имеет большого значения, поскольку идентификатор сеанса в любом случае хранится на стороне клиента в файле cookie ... Кроме того, это руководство не работает для последней версии Express.
Aust
1
ссылка на ваше решение просто перенаправляет на socket.ioстраницу github ..?
TJ
8

Я предлагаю не изобретать велосипед полностью. Инструменты, которые вам нужны, уже являются пакетом npm. Думаю, это то, что вам нужно: session.socket.io Я использую его сейчас, и я думаю, это будет очень полезно !! Связывание экспресс-сессии со слоем socket.io даст множество преимуществ!

Франческо
источник
6
Вот обновленный модуль, который поддерживает socket.io-express-sessions для socket.io> = 1.0 github.com/xpepermint/socket.io-express-session
blnc
4

Изменить: попробовав некоторые модули, которые не работали, я фактически пошел и написал свою собственную библиотеку для этого. Бесстыдный плагин: проверьте его на https://github.com/aviddiviner/Socket.IO-sessions . Я оставлю свой старый пост ниже в исторических целях:


Я получил эту работу довольно аккуратно, не обходя транспорт flashsocket в соответствии с решением pr0zac выше. Я также использую экспресс с Socket.IO. Вот как.

Сначала передайте в представление идентификатор сеанса:

app.get('/', function(req,res){
  res.render('index.ejs', {
    locals: { 
      connect_sid: req.sessionID
      // ...
    }
  });
});

Затем, на ваш взгляд, свяжите его с клиентской стороной Socket.IO:

<script>
  var sid = '<%= connect_sid %>';
  var socket = new io.Socket();
  socket.connect();
</script>
<input type="button" value="Ping" onclick="socket.send({sid:sid, msg:'ping'});"/>

Затем в вашем серверном слушателе Socket.IO возьмите его и прочитайте / запишите данные сеанса:

var socket = io.listen(app);
socket.on('connection', function(client){
  client.on('message', function(message){
    session_store.get(message.sid, function(error, session){
      session.pings = session.pings + 1 || 1;
      client.send("You have made " + session.pings + " pings.");
      session_store.set(message.sid, session);  // Save the session
    });
  });
});

В моем случае session_storeэто Redis, использующий redis-connectбиблиотеку.

var RedisStore = require('connect-redis');
var session_store = new RedisStore;
// ...
app.use(express.session({ store: session_store }));

Надеюсь, это поможет кому-то, кто найдет этот пост во время поиска в Google (как и я;)

Дэйв
источник
8
Помещение идентификатора сеанса в клиентский html - не лучшая идея с точки зрения безопасности ...
UpTheCreek,
4
Почему размещение идентификатора сеанса в HTML - такая плохая идея, если идентификатор сеанса уже хранится в локальном файле cookie?
Gavin
3
Поскольку файлы cookie не могут быть доступны из javascript, если они установлены как HttpOnly cookie. Помещая session.sid в HTML, вы даете злоумышленнику все необходимое в DOM.
Рочал
3

См. Это: Аутентификация Socket.IO

Я бы посоветовал ничего не получать через client.request...или, client.listener...поскольку это не связано напрямую с clientобъектом и всегда указывает на последнего зарегистрированного пользователя!

Шрипад Кришна
источник
2

Проверьте Socket.IO-connect

Подключите WebSocket Middleware Wrapper вокруг Socket.IO-узла https://github.com/bnoguchi/Socket.IO-connect

Это позволит вам протолкнуть запросы Socket.IO вниз по стеку промежуточного программного обеспечения Express / Connect, прежде чем обрабатывать их обработчиками событий Socket.IO, предоставляя вам доступ к сеансу, файлам cookie и многому другому. Хотя я не уверен, что он работает со всеми транспортами Socket.IO.

BMiner
источник
к сожалению, этот модуль до сих пор использует v0.6 из socket.io
fent
2

Вы можете использовать express-socket.io-session .

Поделитесь промежуточным программным обеспечением экспресс-сеанса на основе файлов cookie с socket.io. Работает с express> 4.0.0 и socket.io> 1.0.0 и не будет обратно совместимой.

Сработало у меня !!

Nonybrighto
источник
Привет. Как бы вы использовали значения сеанса во внешнем интерфейсе? Я не вижу их в документах npm.
Hari Ram
1

Вы можете посмотреть на это: https://github.com/bmeck/session-web-sockets

или, в качестве альтернативы, вы можете использовать:

io.on('connection', function(client) { 
  var session = client.listener.server.viewHelpers; 
  // use session here 
});

Надеюсь это поможет.

интеллигент
источник
Я знаю сеансовые веб-сокеты, но я не хочу использовать для этого библиотеку, я ищу простое решение. Я пробовал client.listener.server.viewHelpers; но он вернул это: {}
sfs
2
хотя сначала кажется, что это работает, это приводит к условиям гонки. Я предлагаю вам полностью избегать этого.
Шрипад Кришна
1

Я не уверен, что делаю это правильно. https://github.com/LearnBoost/socket.io/wiki/Authorizing

С данными рукопожатия вы можете получить доступ к файлам cookie. А в файлах cookie вы можете получить connect.sid, который является идентификатором сеанса для каждого клиента. А затем используйте connect.sid для получения данных сеанса из базы данных (я предполагаю, что вы используете RedisStore)

Тан Нгуен
источник
это именно то, что нужно, но вы не круты, поэтому вы не можете получить точки переполнения стека. github.com/tcr/socket.io-session и github.com/functioncallback/session.socket.io Мне первый нравится немного больше, его чище. Второй документ немного лучше документирован.
Джеймс
@TJ Я сожалею об этом, но понимаете ли вы, что ответ был 2 года назад? И, наверное, сейчас это не сработает
Тан Нгуен
@TanNguyen Я знаю, вот почему я уведомил вас, чтобы вы могли обязательно обновить ответ, а не указывать людям на мертвые ссылки
TJ
@TJ Спасибо за это. К сожалению, 2 года назад я отказался от socket.io из-за проблем с производительностью. Поэтому я не знаю, как в настоящее время работать с сеансом в socket.io
Тан Нгуен