Socket.io и выразить 4 сеанса
Я хотел бы получить доступ к экспресс-сессии 4 в приложении socket.io.
Я вроде как новый с Node, и у меня есть некоторые проблемы, реализующие эту функциональность.
Я нашел модуль npm, который позволяет получить доступ к сеансу Express 4: https://www.npmjs.org/package/session.socket.io-express4 или https://github.com/eiriklv/session.socket.io
Если вы посмотрите на мой код app.js ниже, я делаю что-то неправильно в настройках session
, sessionStore
или cookieParser
, потому что я просто не могу заставить этот модуль работать.
// init modules
var express = require('express');
var helmet = require('helmet');
var fs = require('fs');
var path = require('path');
var favicon = require('static-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
var memoryStore = session.MemoryStore;
var app = express();
// set variables
var options = {
key: fs.readFileSync('./openssl_keys/server_key.pem'),
cert: fs.readFileSync('./openssl_keys/server_cert.pem')
};
var cookieSecret = "secret phrase";
var sessionStore = new memoryStore();
app.set('env', process.env.NODE_ENV || 'development');
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(favicon());
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(cookieParser(cookieSecret));
app.use(session({
secret: cookieSecret,
cookie: {httpOnly: true, secure: true},
store: sessionStore
}));
app.use(function(req, res, next){
res.locals.session = req.session;
next();
});
app.use(express.static(path.join(__dirname, 'public')));
//routes
require('./routes/index')(app);
require('./routes/test')(app);
// starting http and https servers
var http = require('http').createServer(app).listen(8000, function(){
console.log("http server listening on port 8000");
});
var https = require('https').createServer(options, app).listen(8080, function(){
console.log("https server listening on port 8080");
});
// starting socket.io & session handler
var serverIO = require('socket.io').listen(https);
var SessionSockets = require('session.socket.io-express4');
var io = new SessionSockets(serverIO, sessionStore, cookieParser);
io.on('connection', function(err, socket, session){
if(err) throw err;
console.log("connected");
//console.log(session);
socket.on('clientMessage', function(content) {
console.log("received client message")
console.log(content);
});
});
module.exports = app;
Я попробовал несколько возможностей:
- Отключение сервера
https
.
- Настройка объекта
cookieParser
с секретной фразой (поэтому он "фактически" экспортирует секретную фразу в io = new SessionSockets(serverIO, sessionStore, cookieParser);
)
- Использование минимальных
cookie
опций.
В любом случае, я немного потерял это, любые предложения/критики приветствуются.
ОБНОВЛЕНИЕ
Хорошо, поэтому после многочисленных попыток я думаю, что смогу заставить его работать!
Проблема заключается в инициализации cookieParser, которая выглядит правильно:
var cookieParser = require('cookie-parser');
app.use(cookieParser());
app.use(session({
secret: "secret phrase",
cookie: {httpOnly: true, secure: true},
store: sessionStore
}));
var io = new SessionSockets(serverIO, sessionStore, cookieParser());
Обратите внимание, что если я использую var io = new SessionSockets(serverIO, sessionStore, cookieParser);
(вместо cookieParser()
), он не работает. Кажется, проблема.
Если я использую:
app.use(cookieParser("secret phrase"));
app.use(session({
secret: "secret phrase",
cookie: {httpOnly: true, secure: true},
store: sessionStore
}));
var io = new SessionSockets(serverIO, sessionStore, cookieParser("secret phrase"));
тогда модуль выходит из строя со следующим сообщением об ошибке:
session.socket.io-express4/session.socket.io.js:41
ake.signedCookies[key] = handshake.signedCookies[key].match(/\:(.*)\./).pop();
^
TypeError: Cannot call method 'pop' of null
Но если я использую:
app.use(cookieParser("secret phrase"));
app.use(session({
secret: "secret phrase",
cookie: {httpOnly: true, secure: true},
store: sessionStore
}));
var io = new SessionSockets(serverIO, sessionStore, cookieParser());
Тогда все выглядит нормально.
Теперь в файле cookie-parser doc (https://github.com/expressjs/cookie-parser), в котором говорится, что вы можете передать секретный ключ, чтобы получить подписанные файлы cookie. Это то, что я хотел бы иметь.
Может ли кто-нибудь объяснить мне связь с секретной фразой cookie-parser и секретной фразой сеанса? Должны ли они быть одинаковыми/разными?
Ответы
Ответ 1
Здесь мое решение для следующей среды:
- express 4.2.0
- socket.io 1.1.0
- cookie-parser 1.0.1
- cookie-session 1.0.2
код:
var cookieParser = require('cookie-parser')();
var session = require('cookie-session')({ secret: 'secret' };
...
app.use(cookieParser);
app.use(session);
...
io.use(function(socket, next) {
var req = socket.handshake;
var res = {};
cookieParser(req, res, function(err) {
if (err) return next(err);
session(req, res, next);
});
});
Затем вы можете получить доступ к сеансу из квитирования сокета:
io.on('connection', function (socket) {
console.log("Session: ", socket.handshake.session);
});
Для людей интересно, как и почему это работает:
- Мы отправляем запрос
handshake
через парсер cookie, чтобы файлы cookie были доступны
- Затем мы отправляем промежуточное ПО
handshake
через сеанс, как если бы его обычный запрос
- Среднее ПО прикрепляет
session
к запросу
- Мы используем
handshake
, потому что для всех целей и задач это обычный запрос, а промежуточное ПО анализатора и сеанса может справиться с ним должным образом. Вот почему вы должны получить доступ к session
через handshake
Ответ 2
С новым промежуточным программным обеспечением экспресс-сессии вам нужно только добавить промежуточное ПО IO:
io.use(function(socket, next) {
session(socket.handshake, {}, next);
});
Полный пример будет выглядеть следующим образом:
var io = require('socket.io')(server);
var Session = require('express-session'),
SessionStore = require('session-file-store')(Session);
session = Session({
store: new SessionStore({ path: './tmp/sessions' }),
secret: 'pass',
resave: true,
saveUninitialized: true
});
io.use(function(socket, next) {
session(socket.handshake, {}, next);
});
io.on('connection', function(socket){
console.log('a user connected');
socket.emit('chat message', "UserID: " + socket.handshake.session.uid);
});
Я создал супер мини-пакет npm socket.io-express-session, который работает, как я объяснил выше.
Ответ 3
Это сработало для меня с
- express 4.9.0
- express.io 1.1.13
- connect-redis 2.1.0
- Экспресс-сессия 1.8.2
То, что я хотел, заключалось в том, чтобы совместно использовать сеансы с интерфейсом и интерфейсом API через redis.
Отдельные машины, имеющие один и тот же БД. Сеансы создаются, и пользователи регистрируются при открытии страницы в интерфейсе, а затем api просматривает зарегистрированных пользователей по запросам.
var cookieParser = require('cookie-parser')();
var session = require('express-session');
var RedisStore = require('connect-redis')(session);
var db = require('./db')(config);
var sessionStore = session( {
store: new RedisStore({ client: db }),
secret: SECRET,
cookie: { secure: false }
}
);
app.use(cookieParser);
app.use(sessionStore);
// attach sessions to pure websocket requests
app.io.use(function(req, next) {
var res = {};
cookieParser(req, res, function(err) {
if (err) { return next(err); }
sessionStore(req, res, next);
});
});
Примечание. Я установил для файла cookie.secure значение false, чтобы я мог тестировать локально без https.
Ответ 4
Это может работать express 4/socket.io 1.X
Я схватил эту форму кода https://github.com/turbonetix/bus.io/blob/master/demo/chat/app.js
io.use(function (socket, next) {
var handshake = socket.handshake;
if (handshake.headers.cookie) {
cookieParser()(handshake, {}, function (err) {
handshake.sessionID = connect.utils.parseSignedCookie(handshake.cookies[config.session.key], config.session.secret);
handshake.sessionStore = config.session.store;
handshake.sessionStore.get(handshake.sessionID, function (err, data) {
if (err) return next(err);
if (!data) return next(new Error('Invalid Session'));
handshake.session = new session.Session(handshake, data);
next();
});
});
}
else {
next(new Error('Missing Cookies'));
}
});
Ответ 5
мне было трудно найти правильное решение. Вот что работает для меня:
/*
Just to see, before my code :
var sessionStore = new mongoStore({
db: db.connection.db,
collection: config.sessionCollection
});
app.use(session({
secret: config.sessionSecret,
store: sessionStore
}));
*/
io.use(function(socket, next) {
var handshake = socket.handshake;
if (handshake.headers.cookie) {
cookieParser(config.sessionSecret)(handshake, {}, function(err) {
handshake.sessionID = handshake.signedCookies['connect.sid']; // <- 'connect.sid' > your key could be different, but this is the default
handshake.sessionStore = sessionStore;
handshake.sessionStore.get(handshake.sessionID, function(err, data) {
if (err) return next(err);
if (!data) return next(new Error('Invalid Session'));
handshake.session = new session.Session(handshake, data);
next();
});
});
} else {
next(new Error('Missing Cookies'));
}
});
express 4.2.0/socket.io 1.0.6
Ответ 6
express-socket.io-session - это готовое решение для вашей проблемы. Обычно сеанс, созданный в socket.io end, имеет различный sid, чем те, что созданы в express.js
Прежде чем зная этот факт, когда я работал над этим, чтобы найти решение, я нашел что-то немного странное. Сессии, созданные из экземпляра express.js, были доступны в конце socket.io, но то же самое было невозможно для противоположного. И вскоре я узнал, что мне нужно проделать свой путь через управление sid, чтобы решить эту проблему. Но для решения этой проблемы уже был составлен пакет. Он хорошо документирован и выполняет свою работу. Надеюсь, что это поможет.
Ответ 7
выразить 4.13.4/socket.io 1.4.5
Я просматриваю все решения и модули, но все они не работают в моем приложении.
Окончательный -
app.use(session({
secret: COOKIE_SECRET,
resave: true,
saveUninitialized: true,
store:sessionStore,
cookie: { domain: 'localhost',secure: false }
}));
io.use(function(socket, next) {
session({
secret: COOKIE_SECRET,
resave: true,
saveUninitialized: true,
store:sessionStore,
cookie: { domain: 'localhost',secure: false }
})(socket.handshake, {}, next);
});
работает как шарм.