我目前正在尝试为我的node.js应用设置基本身份验证系统。目前我使用express(3.0.0rc5),passport(0.1.12)和socket.io(0.9.10)与Mongoose作为会话数据存储。我也一直在玩everyauth
,但我不喜欢与承诺合作。
现状:
通过护照进行身份验证(Facebook策略)成功,在重定向后在客户端上设置了session.sid
cookie,我能够在我的数据库中看到会话文档。我可以通过socket.io
访问socket.handshake.headers.cookie
中的会话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
来访问相应的电子邮件地址。
我该怎么做?任何指针都非常受欢迎。
答案 0 :(得分:61)
以下是使用 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)。您可以使用任何适合您喜欢的会话存储。有关会话存储列表,请参阅the Connect wiki。
答案 1 :(得分:31)
我得到了它的工作。我必须要访问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
答案 2 :(得分:0)
您可以使用express-socket.io-session。您可以使用socket.handshake.session.passport.user
获取护照会话用户。它支持读取和写入会话存储。
NB:使用express> 4.0.0和socket.io> 1.0.0并且不会向后兼容