2012-08-29 89 views
17

我試圖做一個基於Node.js的聊天應用程序。我想強制websocket服務器(ws庫)使用ExpressJS會話系統。不幸的是,我卡住了。用於獲取會話數據的MemoryStore散列與Cookie中的會話ID不同。有人能解釋我做錯了什麼嗎?ExpressJS&Websocket&會話共享

的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 
}); 

應用配置:主代碼

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); 

樣品調試輸出:

- 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

簡單,難看的解決方法有助於:sessionID的= sessionID.match(/:[A-ZA-Z0-9/+] + \ ./)[0]。切片(1,-1),但我想解決這個問題。 – skorczan

+0

感謝您的解決方法,幫助我:)你有沒有找到一個適當的解決方案呢? – Tim

回答

16

我能得到這個工作。我認爲你需要在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); 
    }); 
    }); 

}); 
14

我發現這對我的作品。不知道這是做到這一點的最佳方式。首先,初始化您的快速應用程序:

// 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模塊,則中間件將自行解析Cookie。否則,您可能需要先通過您的cookie解析中間件發送它。

如果您使用的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); 
+4

謹慎解釋downvote? – Azmisov

+0

晚會有點晚,但你的代碼不會編譯。最後一行缺少')' –

+0

@matejkramny謝謝,現在修復 – Azmisov

0

目前,以下是我的解決方法,它工作正常。我只是不知道它的缺點和安全性。如果服務器沒有會話,我只是阻止服務器進行監聽。 (Share session from express-session to ws

雖然我還沒有完全測試過。

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(){}); 
    } 
}); 
0

WS V3.0.0及以上,改變了行爲,因此給定的答案將不是出於這些版本中框的工作。對於當前版本,連接方法的簽名是[function(socket,request)],並且套接字不再包含對請求的引用。

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

在版本3.2.0的ws中,您必須稍微改變一下。

ws回購中有一個full working example快速會話解析,具體使用新功能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}`) 
    }) 
})