node.js ExpressJS & Websocket & 会话共享

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12182651/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 16:14:33  来源:igfitidea点击:

ExpressJS & Websocket & session sharing

node.jssessionwebsocketexpress

提问by skorczan

I'm trying to make a chat application based on Node.js. I'd like to force websocket server (ws library) to using ExpressJS session system. Unfortunately, I've got stuck. MemoryStore hashes used to get sessions' data are different than session IDs in cookies. Could somebody explain me what I'm doing wrong?

我正在尝试基于 Node.js 制作一个聊天应用程序。我想强制 websocket 服务器(ws 库)使用 ExpressJS 会话系统。不幸的是,我被卡住了。用于获取会话数据的 MemoryStore 哈希与 cookie 中的会话 ID 不同。有人可以解释一下我做错了什么吗?

Websocket server code part:

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

store object definition:

存储对象定义:

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

app 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"
    }));
});

Part of main code:

部分主要代码:

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

Sample debugging output:

示例调试输出:

- 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"

回答by Azmisov

I found this works for me. Not sure it's the best way to do this though. First, initialize your express application:

我发现这对我有用。不确定这是最好的方法。首先,初始化您的快递应用程序:

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

Now, explicitly call the session middleware from the WS connection. If you're using the express-sessionmodule, the middleware will parse the cookies by itself. Otherwise, you might need to send it through your cookie-parsing middleware first.

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

If you're using the websocketmodule:

如果您正在使用该websocket模块:

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

If you're using the wsmodule:

如果您正在使用该ws模块:

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

For your convenience, here is a fully working example, using express, express-session, and ws:

为方便起见,这里是一个完全工作的例子,使用expressexpress-session以及ws

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

回答by StereoSteve

I was able to get this working. I think you need to specify the secret on cookieParser instead of session store.

我能够让这个工作。我认为您需要在 cookieParser 而不是会话存储上指定秘密。

Example from my app:

我的应用程序示例:

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

});

回答by sshow

In version 3.2.0 of wsyou have to do it a bit differently.

在 3.2.0 版中,ws你必须做一些不同的事情。

There is a full working exampleof express session parsing in the wsrepo, specifically using a new feature verifyClient.

存储库中有一个快速会话解析的完整工作示例ws,特别是使用新功能verifyClient

A very brief usage summary:

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

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}`)
  })
})

回答by Wing

WS v3.0.0 and above, has changed the behaviour so the given answers won't work out of the box for those versions. For current versions, the signature of the connection method is [function(socket, request)] and the socket no longer contains a reference to the request.

WS v3.0.0 及更高版本更改了行为,因此给定的答案不适用于这些版本。对于当前版本,连接方法的签名是 [function(socket, request)] 并且套接字不再包含对请求的引用。

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

回答by Gabriel Ponce Laureta

Currently, below is my workaround which is working fine. I just don't know it's disadvantages and security. I just prevent the server from listening if it doesn't have a session. (Share session from express-session to ws)

目前,以下是我的工作正常的解决方法。我只是不知道它的缺点和安全性。如果服务器没有会话,我只是阻止它进行侦听。(从 express-session 到 ws 的共享会话

I haven't fully tested this though.

不过我还没有完全测试过这个。

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