30

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

アプリの構成:

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

5 に答える 5

26

私はこれが私のために働くことがわかりました。ただし、これが最善の方法であるかどうかはわかりません。まず、Express アプリケーションを初期化します。

// 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-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);
于 2015-01-01T00:31:25.750 に答える
17

これを機能させることができました。セッションストアではなく、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);
    });
  });

});
于 2013-05-06T08:55:31.567 に答える
9

2022 年 2 月の更新:

verifyClient今は落胆しています。これを行う新しい方法はissue コメントに記載されています。

完全な使用例については、セッションの解析と検証のサンプル コードを参照してください。検証関数のサンプル:

server.on('upgrade', function (request, socket, head) {
  console.log('Parsing session from request...');

  sessionParser(request, {}, () => {
    if (!request.session.userId) {
      socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
      socket.destroy();
      return;
    }

    console.log('Session is parsed!');

    wss.handleUpgrade(request, socket, head, function (ws) {
      wss.emit('connection', ws, request);
    });
  });
});

元の答え:

のバージョン 3.2.0wsでは、少し異なる方法で行う必要があります。

リポジトリには、特に新しい機能を使用した高速セッション解析の完全な実例があります。wsverifyClient

非常に簡単な使用方法の要約:

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}`)
  })
})
于 2017-11-03T14:15:22.663 に答える