我想在我的socket.io应用程序中访问express 4会话。 我是Node的新手,我在实现这个功能方面遇到了一些麻烦。
我找到了一个允许访问快速4会话的npm模块: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解析器文档(https://github.com/expressjs/cookie-parser)中,它说您可以传递密钥以获取Cookie签名。这是我想要的东西。
有人可以解释我与cookie解析器密码短语和会话密码短语的关系吗?他们必须是相同/不同的吗?
答案 0 :(得分:20)
以下是我对以下环境的解决方案:
代码:
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可用handshake
,就像它是正常请求一样session
附加到请求handshake
因为所有意图和目的,它是一个正常的请求,解析器和会话中间件可以正确处理它。这就是您必须通过session
handshake
的原因
答案 1 :(得分:13)
使用新的快速会话中间件,您所要做的就是添加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,其工作原理如上所述。
答案 2 :(得分:2)
这对我有用
我想要的是通过redis与前端和后端API共享会话。 独立的机器,共享相同的数据库。创建会话并在用户在前端打开页面时登录,然后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进行测试。
答案 3 :(得分:1)
这可能工作表达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'));
}
});
答案 4 :(得分:1)
表示 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);
});
像魅力一样工作。
答案 5 :(得分:0)
这让我很难找到合适的解决方案。这对我有用:
/*
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'));
}
});
表示4.2.0 / socket.io 1.0.6
答案 6 :(得分:0)
express-socket.io-session是针对您的问题的现成解决方案。通常,在socket.io end创建的会话与在express.js
中创建的会话具有不同的sid在了解这个事实之前,当我通过它来寻找解决方案时,我发现了一些有点奇怪的东西。从express.js实例创建的会话可以在socket.io端访问,但相反的情况是不可能的。很快我就知道我必须通过管理sid来解决这个问题。但是,已经有一个包来解决这个问题。它有很好的文档记录,可以完成工作。希望它有所帮助