ExpressJS&Websocket&会话共享

我试图做一个基于Node.js的聊天应用程序。 我想强制websocket服务器(ws库)使用ExpressJS会话系统。 不幸的是,我卡住了。 用于获取会话数据的MemoryStore散列与Cookie中的会话ID不同。 有人能解释我做错了什么吗?

Websocket服务器代码部分:

module.exports = function(server, clients, express, store) { server.on('connection', function(websocket) { var username; function broadcast(msg, from) {...} function handleMessage(msg) {...} express.cookieParser()(websocket.upgradeReq, null, function(err) { var sessionID = websocket.upgradeReq.cookies['sid']; //I see same value in Firebug console.log(sessionID); //Shows all hashes in store //They're shorter than sessionID! Why? for(var i in store.sessions) console.log(i); store.get(sessionID, function(err, session) { websocket.on('message', handleMessage); //other code - won't be executed until sessionID in store websocket.on('close', function() {...}); }); }); }); } 

存储对象定义:

 var store = new express.session.MemoryStore({ reapInterval: 60000 * 10 }); 

应用configuration:

 app.configure(function() { app.use(express.static(app.get("staticPath"))); app.use(express.bodyParser()); app.use(express.cookieParser()); app.use(express.session({ store: store, secret: "dO_ob", key: "sid" })); }); 

主要代码的一部分:

 var app = express(); var httpServer = http.createServer(app); var websocketServer = new websocket.Server({server: httpServer}); httpServer.listen(80); 

示例debugging输出:

 - websocket.upgradeReq.headers.cookie "sid=s%3A64a%2F6DZ4Mab8H5Q9MTKujmcw.U8PJJIR%2BOgONY57mZ1KtSPx6XSfcn%2FQPZ%2FfkGwELkmM" - websocket.upgradeReq.cookies["sid"] "s:64a/6DZ4Mab8H5Q9MTKujmcw.U8PJJIR+OgONY57mZ1KtSPx6XSfcn/QPZ/fkGwELkmM" - i "64a/6DZ4Mab8H5Q9MTKujmcw" 

我能够得到这个工作。 我认为你需要指定cookieParser而不是会话存储的秘密。

从我的应用程序示例:

 var app = express(); var RedisStore = require('connect-redis')(express); var sessionStore = new RedisStore(); var cookieParser = express.cookieParser('some secret'); app.use(cookieParser); app.use(express.session({store: sessionStore})); wss.on('connection', function(rawSocket) { cookieParser(rawSocket.upgradeReq, null, function(err) { var sessionID = rawSocket.upgradeReq.signedCookies['connect.sid']; sessionStore.get(sessionID, function(err, sess) { console.log(sess); }); }); }); 

我发现这对我有用。 不知道这是做到这一点的最好方法。 首先,初始化您的快速申请:

 // whatever your express app is using here... var session = require("express-session"); var sessionParser = session({ store: session_store, cookie: {secure: true, maxAge: null, httpOnly: true} }); app.use(sessionParser); 

现在,显式调用WS连接中的会话中间件。 如果您正在使用express-session模块,则中间件将自行parsingCookie。 否则,您可能需要先通过您的cookieparsing中间件发送它。

如果你使用websocket模块:

 ws.on("request", function(req){ sessionParser(req.httpRequest, {}, function(){ console.log(req.httpRequest.session); // do stuff with the session here }); }); 

如果您使用的是ws模块:

 ws.on("connection", function(req){ sessionParser(req.upgradeReq, {}, function(){ console.log(req.upgradeReq.session); // do stuff with the session here }); }); 

为了您的方便,下面是一个完整的示例,使用expressexpress-sessionws

 var app = require('express')(); var server = require("http").createServer(app); var sessionParser = require('express-session')({ secret:"secret", resave: true, saveUninitialized: true }); app.use(sessionParser); app.get("*", function(req, res, next) { req.session.working = "yes!"; res.send("<script>var ws = new WebSocket('ws://localhost:3000');</script>"); }); var ws = new require("ws").Server({server: server}); ws.on("connection", function connection(req) { sessionParser(req.upgradeReq, {}, function(){ console.log("New websocket connection:"); var sess = req.upgradeReq.session; console.log("working = " + sess.working); }); }); server.listen(3000); 

目前,下面是我的解决方法,工作正常。 我只是不知道它的缺点和安全性。 如果它没有会话,我只是防止服务器听。 ( 从快速会议到ws分享会 )

我还没有完全testing这个。

 var http = require('http'); var express = require('express'); var expressSession = require('express-session'); var router = express.Router(); var app = express(); const server = http.createServer(app); router.get('/', function(req, res, next) { if(req.session.user_id) { // Socket authenticated server.listen(8080, function listening(){}); } }); 

WS v3.0.0及以上版本,已经改变了行为,所以给定的答案将不会在这些版本的框中工作。 对于当前版本,连接方法的签名是[function(socket,request)],并且套接字不再包含对请求的引用。

 ws.on( 'connection', function (socket, req) { sessionParser( req, {}, function() { console.log(req.session); } ); } ); 

ws 3.2.0版本中,你必须做一些改变。

ws repo中有一个完整的快速会话parsing示例 ,具体使用了一个新特性verifyClient

一个非常简短的用法总结:

 const sessionParser = session({ saveUninitialized: false, secret: '$eCuRiTy', resave: false }) const server = http.createServer(app) const wss = new WebSocket.Server({ verifyClient: (info, done) => { console.log('Parsing session from request...') sessionParser(info.req, {}, () => { console.log('Session is parsed!') done(info.req.session.userId) }) }, server }) wss.on('connection', (ws, req) => { ws.on('message', (message) => { console.log(`WS message ${message} from user ${req.session.userId}`) }) })