ExpressJS & Websocket & session sharing
我正在尝试制作一个基于Node.js的聊天应用程序。 我想强制websocket服务器(ws库)使用ExpressJS会话系统。 不幸的是,我被卡住了。 用于获取会话数据的MemoryStore哈希与cookie中的会话ID不同。 有人可以解释一下我在做什么错吗?
Websocket服务器代码部分:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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() {...}); }); }); }); } |
存储对象定义:
1 2 3 | var store = new express.session.MemoryStore({ reapInterval: 60000 * 10 }); |
应用配置:
1 2 3 4 5 6 7 8 9 10 11 | 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" })); }); |
主要代码的一部分:
1 2 3 4 | var app = express(); var httpServer = http.createServer(app); var websocketServer = new websocket.Server({server: httpServer}); httpServer.listen(80); |
示例调试输出:
1 2 3 | - 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" |
我发现这对我有用。虽然不确定这是最好的方法。首先,初始化您的快速申请:
1 2 3 4 5 6 7 | // 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连接中显式调用会话中间件。如果您使用的是
如果您使用的是
1 2 3 4 5 6 | ws.on("request", function(req){ sessionParser(req.httpRequest, {}, function(){ console.log(req.httpRequest.session); // do stuff with the session here }); }); |
如果您使用的是
1 2 3 4 5 6 | ws.on("connection", function(req){ sessionParser(req.upgradeReq, {}, function(){ console.log(req.upgradeReq.session); // do stuff with the session here }); }); |
为了方便起见,下面是使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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("var ws = new WebSocket('ws://localhost:3000');"); }); 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); |
我能够使它工作。我认为您需要在cookieParser而不是会话存储上指定秘密。
我的应用程序中的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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); }); }); }); |
在
一个非常简短的用法摘要:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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}`) }) }) |
WS v3.0.0及更高版本已更改了行为,因此对于这些版本,给定的答案将无法立即使用。对于当前版本,连接方法的签名为[function(socket,request)],并且套接字不再包含对该请求的引用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | ws.on( 'connection', function (socket, req) { sessionParser( req, {}, function() { console.log(req.session); } ); } ); |
目前,下面是我的解决方法,它工作正常。我只是不知道它的缺点和安全性。如果没有会话,我只是阻止服务器监听。 (共享会话从快速会话到ws)
我还没有完全测试。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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(){}); } }); |