Как использовать аттестат с express и socket.io?

В настоящее время я пытаюсь настроить базовую систему аутентификации для моего приложения node.js. На данный момент я использую экспресс (3.0.0rc5), паспорт (0.1.12) и socket.io (0.9.10) с Mongoose в качестве хранилища для данных сеанса. Я также играл сeveryauth но я неМне нравится работать с обещаниями.

Текущая ситуация:

Аутентификация через паспорт (стратегия facebook) прошла успешно,session.sid Cookie устанавливается на клиенте после перенаправления, и я могу видеть документ сеанса в моей базе данных. Я могу получить доступ к сессионному cookie вsocket.io через .socket.handshake.headers.cookie

Если я правильно понял концепцию паспорта, после успешногоauthentication passport.serializeUser называется, что позволяет мне добавить информацию к сеансу. В моем случае наиболее важной информацией является электронная почта, поэтому я настроил сериализатор следующим образом:

passport.serializeUser(function(user, done) {
  done(null, user.email);
});

Теперь я нахожусь в точке, где мне нужно использовать только информацию cookie в моем событии socket.io для извлечения адреса электронной почты из сеанса.

var connect = require('connect'),
    parseSignedCookie = connect.utils.parseSignedCookie,
    cookie            = require('express/node_modules/cookie');

io.on('connection', function(socket) {
    if(socket.handshake.headers.cookie) {
        var cookie = cookie.parse(socket.handshake.headers.cookie);
        var sessionID = parseSignedCookie(cookie['connect.sid'], 'secret');
    }
});

passport.deserializeUser(function(id, done) {
    // so, what is supposed to be done here?
});

Так что если я не ошибаюсь, сейчас стоит задача использоватьdeserializeUser чтобы получить доступ к соответствующему адресу электронной почты.

Как бы я это сделал? Любые указатели высоко ценятся.

Ответы на вопрос(3)

что мне нужно было получить доступ к SessionStore. Вот код на случай, если кто-то еще споткнется об этой конкретной проблеме:

// # app.js

var express     = require('express'),
    routes      = require('./routes'),
    http        = require('http'),
    path        = require('path'),
    app         = express(),
    passport    = require('passport'),
    SessionMongoose = require("session-mongoose"),
    mongooseSessionStore = new SessionMongoose({
        url: "mongodb://localhost/login",
        interval: 120000 
    });

var config       = require('game/config.js'), // holds my whole server configuration
    server       = require('game/lib/server.js');

// save sessionStore to config for later access
config.setSessionStore(mongooseSessionStore);

// configure express to use passport and mongooseSessionStore
app.configure(function(){
    app.set('port', config.port);
    app.set('env', config.environment);
    app.set('dbPrefix', config.dbPrefix);
    app.set('views', __dirname + '/views');
    app.set('view engine', 'jade');
    app.use(express.favicon());
    app.use(express.bodyParser());
    app.use(express.cookieParser());
    app.use(express.session({secret : 'totallysecret', store : mongooseSessionStore })),
    app.use(express.methodOverride());
    app.use(passport.initialize());
    app.use(passport.session());    
    app.use(app.router);
    app.use(express['static'](path.join(__dirname, 'public')));
});

app.get('/', routes.index);

app.get('/auth/facebook', passport.authenticate('facebook', { scope: 'email' }));
app.get('/auth/facebook/callback', 
    passport.authenticate('facebook', { successRedirect: '/',
                                        failureRedirect: '/' })); 

// #### Init httpserver
var httpServer = http.createServer(app);
httpServer.listen(app.get('port'));

// #### Server startup
server.init(httpServer);

Мои функции сериализации выглядят просто так:

passport.serializeUser(function(user, done) {
    // saves user.email to session.passport.user
    done(null, user.email);
});

passport.deserializeUser(function(obj, done) {
    done(null, obj);
});

И, наконец, реализация socket.io:

var util              = require('util'),
    connect           = require('connect'),
    parseSignedCookie = connect.utils.parseSignedCookie,
    cookie            = require('express/node_modules/cookie'),
    io                = require('socket.io').listen(httpServer);

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

io.configure(function () {
    io.set('authorization', function (data, callback) {
        if(data.headers.cookie) {
            // save parsedSessionId to handshakeData
            data.cookie = cookie.parse(data.headers.cookie);
            data.sessionId = parseSignedCookie(data.cookie['connect.sid'], 'totallysecret');
        }
        callback(null, true);
    });

    io.on('connection', function(socket) {
        // reference to my initialized sessionStore in app.js
        var sessionStore = config.sessionStore;
        var sessionId    = socket.handshake.sessionId;

        sessionStore.get(sessionId, function(err, session) {
            if( ! err) {
                if(session.passport.user) {
                    console.log('This is the users email address %s', session.passport.user);
            }
        });
    });
});

Используя модуль session-mongoose, я имею доступ к:

sessionStore.get(sessionId, callback)
sessionStore.set(sessionId, data, callback) 
sessionStore.destroy(sessionId, callback) 
sessionStore.all(callback)    // returns all available sessions
sessionStore.clear(callback)  // deletes all session data
sessionStore.length(callback) // returns number of sessions in the 
Решение Вопроса

Вот решение с использованиемSocket.IO 1.0 и Express 4.0, По духу он похож на Патрикаответ. Хитрость в том, что, поскольку Socket.IO 1.0 имеет новый API промежуточного программного обеспечения, мы можем обернуть Express 'Промежуточное программное обеспечение и поместите его в конвейер Socket.IO, не углубляясь в низкоуровневую реализацию хранилищ сеансов.

// Set up the Session middleware using a MongoDB session store
expressSession = require("express-session");
var sessionMiddleware = expressSession({
    name: "COOKIE_NAME_HERE",
    secret: "COOKIE_SECRET_HERE",
    store: new (require("connect-mongo")(expressSession))({
        url: "mongodb://localhost/DATABASE_NAME_HERE"
    })
});

// Set up the Express server
var app = require("express")()
    .use(sessionMiddleware)
    .use(passport.initialize())
    .use(passport.session())
    // ... more middleware ...
    .listen(8000);

// Set up the Socket.IO server
var io = require("socket.io")(app)
    .use(function(socket, next){
        // Wrap the express middleware
        sessionMiddleware(socket.request, {}, next);
    })
    .on("connection", function(socket){
        var userId = socket.request.session.passport.user;
        console.log("Your User ID is", userId);
    });

ПеременнаяsessionMiddleware это функция, которая предназначена для установки непосредственно в конвейер Express. Он принимает ровно три аргумента: объект запроса, объект ответа и обратный вызов.

Socket.IO»Однако конвейер ожидает, что его промежуточное ПО будет принимать только два аргумента: объект сокета (который содержит объект запроса вsocket.request) и обратный звонок. к счастьюsessionMiddleware не требует, чтобы объект ответа считывал сеанс из хранилища, поэтому мы просто передаем ему пустой объект в качестве второго аргумента.

Обратите внимание, что некоторые комментарии ниже отмечают, что этот код делает сеанс доступным только для чтения. Это функциональность, которую мы теряем, не имея надлежащегоответ объект с Socket.IO.

В приведенном выше примере я использую хранилище сеансов MongoDB (connect-mongo). Вы можете использовать любой магазин сессий по своему вкусу. Ссылаться наConnect wiki для списка магазинов сессий.

 user365842327 мар. 2015 г., 18:12
@ Бен - я получаю ту же ошибку. Вы смогли это исправить?
 Alexander Mills17 сент. 2018 г., 20:16
Интересно, почему этонеsocket.request.user; вместоsocket.request.session.passport.user; ... первое похоже на этобольше в соответствии с Express.js.
 Max Yari28 мар. 2015 г., 21:16
Привет, этот ответ был довольно полезен для меня, но как только я начал копать дальше, я наткнулся на проблему. я не могу ни изменить сессию изнутри сокетов. Единственный способ, который я нашел, - это вручную вызвать .save () в сеансе из хранилища Монго, это сохраняет, но тогда я не могу изменить эти сохраненные значения дальше, они привязаны к первому сохраненному значению.
 Király István15 сент. 2016 г., 03:18
Я получаю эту ошибку URL, а также .. :( TypeError: Parameter 'URL» должна быть строкой, не неопределенной в Url.parse (url.js: 73: 11) в urlParse (url.js: 67: 5) в Array.session (node_modules / express-session / index.js: 98: 24)
 Max Yari28 июн. 2015 г., 13:10
@ClaudiuHojda Session.socket.io предназначен для socket.io < 1.x и этопочти опустился
 Alexander Mills23 июн. 2015 г., 05:45
вопрос: ПатрикОтвет s ясно показывает, что он вручную идет в хранилище сеансов, чтобы получить информацию о сеансе. Но разве это ответ?s функциональность промежуточного программного обеспечения socket.io ("io.use (function (socket, next) {sessionMiddleware (socket.request, {}, next);}); ") читать из MongoStore для вас? или вам нужно самим прочитать идентификатор сессии из MongoStore?
 Claudiu Hojda27 мая 2015 г., 12:59
@MaxYari, sessionMiddleware предоставляет только доступ для чтения, в большинстве случаев этодостаточно. использованиеsession.socket.io также иметь возможность сохранить изнутри розетки.
 Claudiu Hojda28 июн. 2015 г., 14:03
@MaxYarisession.socket.io/example-express4 использует socket.io 1.3.x. С таким промежуточным ПОsocket.io-экспресс-сессия Вы можете только читать, сsession.socket.ioдаже если этоВ старом стиле вы получаете экземпляр Session и можете также сохранить.
 Kaya Toast09 сент. 2014 г., 14:54
Можете ли вы уточнить, что делаетsessionMiddleware(socket.request, {}, next) и как ты это понял? Благодарю.
 Boern08 янв. 2015 г., 16:12
Я получаю ´new TypeError ("Параметр 'URL» должна быть строка, а не + typeof url) ´ ошибка из-за несовпадения пути с socket.io 1.1.0, происходящего из строки ´sessionMiddleware (socket.request, {}, next); ´ и вырос в ´сессия (../server/node_modules/express-session/index.js:98:24)´, Любой совет приветствуется!
 mcfedr12 нояб. 2015 г., 13:27
Если вы также поместите промежуточное ПО для паспорта в socket.io, вы сможете найтиclient.request.user немного меньше копать, не уверен, есть ли какие-либо преимущества в этом пока ...
 Max Yari28 июн. 2015 г., 21:36
@ClaudiuHojda Да, этот пример действительно в старом стиле, и в их документации по github четко сказано, что этот модуль будет устаревшим, и вместо этого используйте sessionmiddleware для сокетов (которые, похоже, не имеют поддержки для записи). Ах, может быть, я просто лучше держать простой объект с парой сеансов / socket.io, и это будет соответствовать моим потребностям
 sffc23 июн. 2015 г., 07:00
@AlexMills Информация о сеансе извлекается из вашего хранилища сеансов внутриsessionMiddleware, На самом деле это точноsessionMiddleware»работа для Экспресса; мы просто манипулируем этим, чтобы работать на Socket.IO.
 sffc11 сент. 2014 г., 01:21
Вверх в разделе Экспресс, когда вы проходитеsessionMiddleware вapp.use(...)Express будет вызывать эту функцию всякий раз, когда получает запрос. По соглашению, Express передает функции три аргумента: объект запроса, объект ответа, а затемnext функция для вызова, когда сделано. Socket.IO v1.0 имеет похожую парадигму, но он передает два аргумента вместо трех: объект сокета иnext функция. Строка, на которую вы ссылаетесь, транслируется между двумя API.
 Max Yari12 мар. 2016 г., 16:29
@sffc, что вы думаете о добавлении связывания промежуточного программного обеспечения для паспорта вместе с промежуточным программным обеспечением сеанса в ваш пример кода? Поскольку вопрос касается фактического использования паспорта, он выглядит немного неполным, если в вашем ответе содержится только промежуточное программное обеспечение сеанса.

экспресс-socket.io-сессия, Вы можете получить пользователя сессии паспорта сsocket.handshake.session.passport.user , Он поддерживает чтение и запись в хранилище сеансов.

NB: работает с экспрессом> 4.0.0 и socket.io> 1.0.0 и выигралбыть обратно совместимым

 jack blank23 мая 2019 г., 08:47
Я понимаю, но как вы получаете объект пользователя, а не идентификатор. Я полагаю, что вы можете выполнять поиск в БД, но с паспортом он делает это автоматически с сеансом и дефибрилляцией. С этим методом этопросто показывает идентификатор
 Abhishek Ranjan10 янв. 2018 г., 20:54
Привет, Можете ли вы дать больше шагов по этому вопросу?

Ваш ответ на вопрос