如何使用express和socket.io使用护照?
我目前正在尝试为我的node.js应用程序设置一个基本的身份validation系统。 现在我使用Express(3.0.0rc5),护照(0.1.12)和socket.io(0.9.10)作为会话数据的Mongoose Store。 我也一直在玩everyauth
但我不喜欢与诺言合作。
现在的情况:
通过护照(脸书策略)身份validation是成功的,在redirect后,客户端上设置session.sid
cookie,我能看到我的数据库中的会话文档。 我可以通过socket.handshake.headers.cookie
访问socket.io
的会话cookie。
如果我正确理解了护照概念,那么在成功authentication passport.serializeUser
后,我就可以将信息添加到会话中。 在我的情况下,最重要的信息是电子邮件,所以我按照以下方式设置序列化程序:
passport.serializeUser(function(user, done) { done(null, user.email); });
现在我处于必须只使用我的socket.io事件中的cookie信息从会话中提取电子邮件地址的地步。
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
来访问相应的电子邮件地址。
我该怎么做? 任何指针,高度赞赏。
这是一个使用Socket.IO 1.0和Express 4.0的解决scheme。 这与帕特里克的答案精神相似。 诀窍是,由于Socket.IO 1.0有一个新的中间件API,所以我们可以将Express的中间件封装到Socket.IOpipe道中,而不需要深入讨论会话存储的低级实现。
// 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); });
variablessessionMiddleware是一个函数,它被devise成直接适合Expresspipe道。 它只需要三个参数:请求对象,响应对象和callback。
Socket.IO的pipe道期望它的中间件只接受两个参数:socket对象(包含socket.request请求对象)和callback。 幸运的是, sessionMiddleware不需要响应对象从商店读取会话,所以我们只需将它作为第二个parameter passing给一个空对象。
请注意,下面的一些注释观察到,此代码呈现会话只读。 这是我们失去的function,因为没有与Socket.IO适当的响应对象。
在上面的例子中,我使用了一个MongoDB会话存储(connect-mongo)。 你可以使用任何会议商店适合你的喜好。 请参阅Connect维客获取会话存储列表。
我得到它的工作。 我必须要访问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