LoginSignup
5

More than 1 year has passed since last update.

Passportで認証したユーザ情報をsocket.ioに引き継ぐ

Last updated at Posted at 2019-09-30

2022-11-19 追記
こちらの方法の方がより簡単です(原理は同じ)。


Passport で認証したユーザ情報を socket.io に引き継ぐモジュールを作ってみた。

プログラム

socket.io-passport-session.js
module.exports = (session, passport)=>{
    return {
        express_session:
            (socket, next)=>{session(socket.request, {}, next)},
        passport_initialize:
            (socket, next)=>{passport.initialize()(socket.request, {}, next)},
        passport_session:
            (socket, next)=>{passport.session()(socket.request, {}, next)}
    }
}

利用例

const express  = require('express');
const session  = require('express-session')({
                            secret:'secret',
                            resave:false,
                            saveUninitialized:false });
const passport = require('passport');

const socket_io_session
               = require('./socket.io-passport-session')(session, passport);

const app = express();

app.use(session);
app.use(passport.initialize());
app.use(passport.session());

const server = require('http').createServer(app);
const io = require('socket.io')(server);

io.use(socket_io_session.express_session);
io.use(socket_io_session.passport_initialize);
io.use(socket_io_session.passport_session);

io.on('connection', socket=>{
    console.log(socket.request.user);
    socket.on('hello', msg=>{
        console.log(socket.request.user);
        console.log('hello', msg);
    });
});

server.listen(3000);

動作原理

WebSocketは最初HTTPで接続し、その接続をWebSocketに「流用」する訳だが、最初のHTTPリクエストには認証のための Cookie ヘッダも含まれている。Cookie の値さえ分かればユーザ情報は復元可能なのだが、

  1. Cookie の値からセッションデータを復元
  2. セッションデータからユーザ情報を復元

する手順は express-session と passport に隠蔽されている1。1はミドルウェア関数の session() で、2は passport.session() で処理されるので、これらのミドルウェア関数を呼び出してあげればよい。2

ただし、app.use() から呼び出されるミドルウェアの引数は、(req, res, next) なのに対し、io.use() から呼び出される関数は (socket, next) なので変換が必要になる。具体的には (socket, next)(socket.request, {}, next) とすればよい。

結果のユーザ情報は socket.request.user に設定される。この情報は connect 時だけでなく emit の際にも設定されるようであるが、送信元の識別はユーザ情報ではなく socket.id で行うべき。

npm モジュール

ちょっと手直しして npm に登録しました。

  1. 2はアプリ側が passport.deserializeUser() で指定するので方法は自明だが、指定済みの方法を参照すべき

  2. passport.session() の前処理を passpport.initialize() で行うので、このミドルウエア関数も呼び出す必要あり

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5