Socket.IO 1.x ve Express 4.x ile oturumlar nasıl paylaşılır?


91

Socket.io 1.0 ve Express 4.x ile bir oturumu nasıl paylaşabilirim? Bir Redis Mağazası kullanıyorum, ancak önemi olmaması gerektiğine inanıyorum. Çerezlere bakmak ve oturumu getirmek için bir ara yazılım kullanmam gerektiğini biliyorum, ancak nasıl yapılacağını bilmiyorum. Aradım ama herhangi bir çalışma bulamadım

    var RedisStore = connectRedis(expressSession);
    var session = expressSession({
        store: new RedisStore({
            client: redisClient
        }),
        secret: mysecret,
        saveUninitialized: true,
        resave: true
    });
    app.use(session);

    io.use(function(socket, next) {
        var handshake = socket.handshake;
        if (handshake.headers.cookie) {
            var str = handshake.headers.cookie;
            next();
        } else {
            next(new Error('Missing Cookies'));
        }
    });

Yanıtlar:


219

Çözüm şaşırtıcı derecede basit. Sadece çok iyi belgelenmemiş. Ekspres oturum ara yazılımını aşağıdaki gibi küçük bir adaptörle Socket.IO ara yazılım olarak kullanmak mümkündür:

sio.use(function(socket, next) {
    sessionMiddleware(socket.request, socket.request.res, next);
});

Ekspres 4.x, Socket.IO 1.x ve Redis ile tam bir örnek:

var express = require("express");
var Server = require("http").Server;
var session = require("express-session");
var RedisStore = require("connect-redis")(session);

var app = express();
var server = Server(app);
var sio = require("socket.io")(server);

var sessionMiddleware = session({
    store: new RedisStore({}), // XXX redis server config
    secret: "keyboard cat",
});

sio.use(function(socket, next) {
    sessionMiddleware(socket.request, socket.request.res || {}, next);
});

app.use(sessionMiddleware);

app.get("/", function(req, res){
    req.session // Session object in a normal request
});

sio.sockets.on("connection", function(socket) {
  socket.request.session // Now it's available from Socket.IO sockets too! Win!
});


server.listen(8080);

18
Çözümünüz konusunda bana yardım edebilir misiniz? Sadece bu verileri {çerez almak: { path: '/', _expires: null, originalMaxAge: null, httpOnly: true, secure: true } }Ama benim rotalara oturumu yazdırmak eğer ben kurdum tüm oturum değişkenleri (kullanıcı adı, kimliği, vb ..) almak
Bobby köpekbalığı

7
Bu tamamen dokümanlarına eklenmelidir. Kimlik doğrulama belgeleri şu anda olduğu gibi süper hafiftir.
Bret

4
bu benim için "işe yarıyor", ancak Express oturum kimliğim socket.io oturum kimliğimle aynı değil ... belki yine de onların aynı olmasını istemiyorum?
Alexander Mills

4
Bu çözüm BÜYÜK çalıştı! ... veriyi bir soketten oturuma kaydetmem gerekene kadar. on () bu noktada bunun tek yol olduğunu görüyorum. Her iki şekilde de çalışmasını sağlamanın bir yolu var mı?
iDVB

4
Bu, birkaç değişiklikle harika çalıştı. Ama socket.io'dan oturuma yazamadım. Tüm ihtiyaçlarımı karşılayan ve bu cevabın uygulanması için hemen hemen aynı çabayı gösteren bir UÖM paketi buldum. npmjs.com/package/express-socket.io-session
Bacon Brad

6

Sadece bir buçuk ay önce aynı problemle uğraştım ve daha sonra bu konu hakkında GitHub'da barındırılan tam olarak çalışan bir demo uygulamasıyla birlikte gelen kapsamlı bir blog yazısı yazdım . Çözüm , her şeyi bağlamak için express-session , cookie-parser ve connect-redis node modüllerine dayanır . Oldukça kullanışlı olan hem REST hem de Sockets bağlamından oturumlara erişmenize ve bunları değiştirmenize olanak tanır.

İki önemli bölüm ara yazılım kurulumudur:

app.use(cookieParser(config.sessionSecret));
app.use(session({
    store: redisStore,
    key: config.sessionCookieKey,
    secret: config.sessionSecret,
    resave: true,
    saveUninitialized: true
}));

... ve SocketIO sunucu kurulumu:

ioServer.use(function (socket, next) {
    var parseCookie = cookieParser(config.sessionSecret);
    var handshake = socket.request;

    parseCookie(handshake, null, function (err, data) {
        sessionService.get(handshake, function (err, session) {
            if (err)
                next(new Error(err.message));
            if (!session)
                next(new Error("Not authorized"));

            handshake.session = session;
            next();
        });
    });
});

Yaptığım basit bir sessionService modülü ile birlikte gidiyorlar, bu da oturumlarla bazı temel işlemleri yapmanıza izin veriyor ve bu kod şuna benziyor:

var config = require('../config');

var redisClient = null;
var redisStore = null;

var self = module.exports = {
    initializeRedis: function (client, store) {
        redisClient = client;
        redisStore = store;
    },
    getSessionId: function (handshake) {
        return handshake.signedCookies[config.sessionCookieKey];
    },
    get: function (handshake, callback) {
        var sessionId = self.getSessionId(handshake);

        self.getSessionBySessionID(sessionId, function (err, session) {
            if (err) callback(err);
            if (callback != undefined)
                callback(null, session);
        });
    },
    getSessionBySessionID: function (sessionId, callback) {
        redisStore.load(sessionId, function (err, session) {
            if (err) callback(err);
            if (callback != undefined)
                callback(null, session);
        });
    },
    getUserName: function (handshake, callback) {
        self.get(handshake, function (err, session) {
            if (err) callback(err);
            if (session)
                callback(null, session.userName);
            else
                callback(null);
        });
    },
    updateSession: function (session, callback) {
        try {
            session.reload(function () {
                session.touch().save();
                callback(null, session);
            });
        }
        catch (err) {
            callback(err);
        }
    },
    setSessionProperty: function (session, propertyName, propertyValue, callback) {
        session[propertyName] = propertyValue;
        self.updateSession(session, callback);
    }
};

Her şeyde bundan daha fazla kod olduğundan (modülleri başlatmak, hem istemci hem de sunucu tarafında soketler ve REST çağrıları ile çalışmak gibi), tüm kodu buraya yapıştırmayacağım, GitHub'da görüntüleyebilirsiniz. ve onunla ne istersen yapabilirsin.


4

express-socket.io-session

probleminiz için hazır bir çözümdür. Normalde socket.io ucunda oluşturulan oturum, express.js'de oluşturulanlardan farklı bir sid'e sahiptir.

Bunu bilmeden önce, çözümü bulmak için üzerinde çalışırken biraz tuhaf bir şey buldum. Express.js örneğinden oluşturulan oturumlara socket.io ucundan erişilebilir, ancak tam tersi için aynısı mümkün değildi. Ve çok geçmeden, bu sorunu çözmek için Sid'i yöneterek kendi yolumda çalışmam gerektiğini anladım. Ancak zaten bu tür bir konuyu ele almak için yazılmış bir paket vardı. İyi belgelenmiştir ve işi bitirir. Umarım yardımcı olur


2

Bradley Lederholz'un cevabını kullanarak, bu şekilde kendim için çalışmasını sağladım. Daha fazla açıklama için lütfen Bradley Lederholz'un cevabına bakın.

var app = express();
var server  = require('http').createServer(app);
var io = require('socket.io');
var cookieParse = require('cookie-parser')();
var passport = require('passport');
var passportInit = passport.initialize();
var passportSession = passport.session();
var session = require('express-session');
var mongoStore = require('connect-mongo')(session);
var mongoose = require('mongoose');
var sessionMiddleware = session({
  secret: 'some secret',
  key: 'express.sid',
  resave: true,
  httpOnly: true,
  secure: true,
  ephemeral: true,
  saveUninitialized: true,
  cookie: {},
  store:new mongoStore({
  mongooseConnection: mongoose.connection,
  db: 'mydb'
  });
});

app.use(sessionMiddleware);
io = io(server);
io.use(function(socket, next){
  socket.client.request.originalUrl = socket.client.request.url;
  cookieParse(socket.client.request, socket.client.request.res, next);
});

io.use(function(socket, next){
  socket.client.request.originalUrl = socket.client.request.url;
  sessionMiddleware(socket.client.request,   socket.client.request.res, next);
});

io.use(function(socket, next){
  passportInit(socket.client.request, socket.client.request.res, next);
});

io.use(function(socket, next){
  passportSession(socket.client.request, socket.client.request.res, next);
});

io.on('connection', function(socket){
  ...
});

... 
server.listen(8000);

Benim için çalıştı. Socket.request.user benim kullanıcıyı Bulunan
Milazi

0

Ben de çözdüm ama mükemmel değil. İmzalı tanımlama bilgilerini vb. Desteklemiyor. Ekspres oturumun getcookie işlevini kullandım. Değiştirilen işlev aşağıdaki gibidir:

    io.use(function(socket, next) {
        var cookie = require("cookie");
        var signature = require('cookie-signature');
        var debug = function() {};
        var deprecate = function() {};

        function getcookie(req, name, secret) {
            var header = req.headers.cookie;
            var raw;
            var val;

            // read from cookie header
            if (header) {
                var cookies = cookie.parse(header);

                raw = cookies[name];

                if (raw) {
                    if (raw.substr(0, 2) === 's:') {
                        val = signature.unsign(raw.slice(2), secret);

                        if (val === false) {
                            debug('cookie signature invalid');
                            val = undefined;
                        }
                    } else {
                        debug('cookie unsigned')
                    }
                }
            }

            // back-compat read from cookieParser() signedCookies data
            if (!val && req.signedCookies) {
                val = req.signedCookies[name];

                if (val) {
                    deprecate('cookie should be available in req.headers.cookie');
                }
            }

            // back-compat read from cookieParser() cookies data
            if (!val && req.cookies) {
                raw = req.cookies[name];

                if (raw) {
                    if (raw.substr(0, 2) === 's:') {
                        val = signature.unsign(raw.slice(2), secret);

                        if (val) {
                            deprecate('cookie should be available in req.headers.cookie');
                        }

                        if (val === false) {
                            debug('cookie signature invalid');
                            val = undefined;
                        }
                    } else {
                        debug('cookie unsigned')
                    }
                }
            }

            return val;
        }

        var handshake = socket.handshake;
        if (handshake.headers.cookie) {
            var req = {};
            req.headers = {};
            req.headers.cookie = handshake.headers.cookie;
            var sessionId = getcookie(req, "connect.sid", mysecret);
            console.log(sessionId);
            myStore.get(sessionId, function(err, sess) {
                console.log(err);
                console.log(sess);
                if (!sess) {
                    next(new Error("No session"));
                } else {
                    console.log(sess);
                    socket.session = sess;
                    next();
                }
            });
        } else {
            next(new Error("Not even a cookie found"));
        }
    });

    // Session backend config
    var RedisStore = connectRedis(expressSession);
    var myStore = new RedisStore({
        client: redisClient
    });
    var session = expressSession({
        store: myStore,
        secret: mysecret,
        saveUninitialized: true,
        resave: true
    });
    app.use(session);

0

Şimdi, kabul edilen orijinal cevap benim için de işe yaramıyor. @ Rahil051 ile aynı, express-socket.io-session modülünü kullandım ve hala çalışıyor. Bu modül, hızlı oturum ara yazılımına girmeden önce oturum kimliğini ayrıştırmak için çerez ayrıştırıcı kullanır. Sanırım @pootzko, @Mustafa ve @ Kosar'ın cevabı silmiar.

Bu modülleri kullanıyorum:

"dependencies": 
{
  "debug": "^2.6.1",
  "express": "^4.14.1",
  "express-session": "^1.15.1",
  "express-socket.io-session": "^1.3.2
  "socket.io": "^1.7.3"
}

socket.handshake içindeki verileri kontrol edin:

const debug = require('debug')('ws');
const sharedsession = require('express-socket.io-session');

module.exports = (server, session) => {
    const io = require('socket.io').listen(server);
    let connections = [];

    io.use(sharedsession(session, {
        autoSave: true,
    }));

    io.use(function (socket, next) {
        debug('check handshake %s', JSON.stringify(socket.handshake, null, 2));
        debug('check headers %s', JSON.stringify(socket.request.headers));
        debug('check socket.id %s', JSON.stringify(socket.id));
        next();
    });

    io.sockets.on('connection', (socket) => {
        connections.push(socket);
    });
};
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.