Как получить постоянный идентификатор экспресс-сессии в соединении socket.io?

Я создаю приложение чата стека MEAN. И я хочу иметь возможность получить идентификатор экспресс-сеанса внутри socket.io в обработчике соединения. Я могу получить доступ к socket.handshake.session.id, но это не то же самое, что req.session.id. Далее socket.handshake.session.id продолжает меняться для каждого сокета.

Я попытался решить эту проблему, получив идентификатор сеанса из req.handshake.cookie, выполнив поиск ключа connect.sid, но этот ключ там не определен.

const cors = require('cors'),
express = require('express'),
eSession = require('express-session'),
cookieParser = require('cookie-parser'),
MongoStore = require('connect-mongo')(eSession),
sharedsession = require('express-socket.io-session'),
http = require('http'),
bodyParser = require('body-parser'),
socketio = require('socket.io');

const app = express();
const server = http.createServer(app);
const io = socketio(server);

const port = process.env.PORT || 3000;
//imports
const mongoose = require('./config/dbconnection');

//routes
const user = require('./api/routes/user');

const socketHandle = (io, mStore) => {
   io.on('connection', (socket) => {
     socket.on('join', (options, callback) => {

     console.log(socket.handshake.headers.cookie); //no connect.sid string present
     console.log(socket.handshake.session.id) // has value but keeps changing on each io connection and this id is not the same as req.session.id in an api endpoint method

    });
  }); 

const corsOptions = {
  origin: 'http://localhost:4200',
  optionsSuccessStatus: 200
};

const db = mongoose.connection;
const mStore = new MongoStore({ mongooseConnection: db });
const session = eSession({
  secret: 'my-secret',
  resave: true,
  saveUninitialized: true,
  store: mStore
});

app.use(cookieParser('my-secret'));
app.use(session);
io.use(sharedsession(session,{autoSave:true}));

socketHandle(io, mStore);

//body-parser
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

app.use(cors(corsOptions));

app.use('/user', user);

server.listen(port, () => console.log(`listening on http://localhost:${port}`));

И socket.handshake.session.id, и socket.handshake.headers.cookie(connect.sid key) должны были предоставить идентификатор сеанса, который имеет то же значение, что и req.session.id.


person Anand Kashyap    schedule 30.08.2019    source источник
comment
вот у меня точно такая же проблема   -  person Fabian Bosler    schedule 15.04.2020


Ответы (3)


@ Ананд Кашьяп прав, если вы позволите экспресс-серверу обслуживать вашего клиента, файл cookie будет присутствовать.

Однако, если ваш клиент находится на другом хосте, вам необходимо передать withCredentials: true конструктору сокета. Это прикрепит файл cookie к запросу, и сеанс будет работать.

const io = require("socket.io-client");

const socket = io("ws://example.com/", {
  withCredentials: true,
  autoConnect: 10000
});
person Alex Tenev    schedule 01.12.2020

Я попробовал это, и у меня это сработало с вашим кодом, поэтому я думаю, что есть что-то с сохранением вашего сеанса. Похоже, что между вашим socket.handshake.session и вашим экспресс-сеансом нет взаимодействия, возможно, потому, что вы неправильно храните его в монго. Попробуйте это, а затем создайте свое приложение вокруг него :)

const express = require('express');
const eSession = require('express-session');
const MongoStore = require('connect-mongo')(eSession);
const mongoose = require('mongoose');
const sharedsession = require('express-socket.io-session');
const http = require('http');
const socketio = require('socket.io');

const app = express();
const server = http.createServer(app);
const io = socketio(server);

const port = process.env.PORT || 3000;

const socketHandle = (io) => {
   io.on('connection', (socket) => {
     console.log(socket.handshake.session.id) // same value on every connection
  }); 
}

// Connect with MongoDB (database called 'test')
mongoose.connect('mongodb://localhost/test', { useNewUrlParser: true, useCreateIndex: true })
    .then(() => console.log('Connected with MongoDB!'))
    .catch(err => console.log(err));

let db = mongoose.connection;

const mStore = new MongoStore({ mongooseConnection: db });
const session = eSession({
  secret: 'my-secret',
  resave: true,
  saveUninitialized: true,
  store: mStore
});

app.use(session);
io.use(sharedsession(session,{autoSave:true}));

socketHandle(io);

// Static folder
app.use(express.static('public')); //Basic html page for socket connection

server.listen(port, () => console.log(`listening on http://localhost:${port}`));

Теперь, если вы заглянете в свою коллекцию сеансов, вы увидите, что она сохранена, а идентификатор совпадает с идентификатором handshake.session.id. Надеюсь, что это работает для вас :)

person Djinii    schedule 02.09.2019
comment
Джинии, нужно ли использовать app.use(express.static('public')) для того же идентификатора сокета? Я пытаюсь подключиться к сокету через ng serve на другом порту. - person Anand Kashyap; 03.09.2019
comment
Нет, не нужно. Я просто сделал это, чтобы попробовать. Убедитесь, что ваш порт такой же, когда вы прослушиваете другой порт. - person Djinii; 05.09.2019
comment
@Djinii Я пробовал ваш пример и получаю разные идентификаторы сеансов, консольный журнал: KOyRyj5icAr3FUWpvoRSoEC3EhZueBZV и в Mongo 0nkOKn5HaUIWg6adm0SaOSRDoSMnh1wR - почему? Я дергаю себя за волосы здесь... - person Fabian Bosler; 15.04.2020

С моим кодом проблем не было. Единственное, что вызывало другой идентификатор сеанса, это тот факт, что я запускал angular на другом порту, а не на сервере узла. Мне пришлось ng build --watch for angular и выводить файлы в папку статических файлов сервера node. Сделав это, я смог получить согласованный идентификатор сеанса как в маршрутах, так и в сокете io.

person Anand Kashyap    schedule 02.10.2019
comment
У меня точно такая же проблема: socket.handshake.session.id: -armMd830gjfhLP7BRXXK3rLWeDDLlNu socket.handshake.headers.cookie: io=s_h5pcLB_9NSXUHLAAAA Кажется, вы решили ее, не могли бы вы немного подробнее объяснить свой ответ? Я также использовал файлы сборки для статической информации, но не повезло. - person Fabian Bosler; 15.04.2020
comment
@FabianBosler, вы храните файлы внешнего интерфейса в статическом каталоге expressjs или нет? - person Anand Kashyap; 15.04.2020
comment
Юпп, я. Создайте пряжу и укажите ссылку на эту папку. - person Fabian Bosler; 15.04.2020
comment
Тогда идентификатор сокета должен был быть таким же. По крайней мере, после создания фронтенда. Можете ли вы поделиться своим кодом экспресс-подключения к сокету и проверки идентификатора - person Anand Kashyap; 19.04.2020