Passport.js+Socket.io+Express中socket.request.user未定义,无法获取userID
看起来你在适配新版Socket.io和Passport时,遇到了用户认证信息无法传递到Socket连接的问题,我来帮你一步步排查和解决:
核心问题分析
你提到socket.request能看到数据,但socket.request.user是undefined,这说明Session数据已经传递到Socket连接了,但Passport没有完成用户的反序列化操作,或者passport.socketio的配置存在错误。
问题1:Session Store的引用错误
你的ioServer代码里,sessionStore直接引用了require("./session"),但这个模块导出的是Express Session中间件,不是Session Store实例。passport.socketio需要的是实际的Store对象,而不是中间件。
修复步骤:
先修改你的Session模块,把Store单独抽出来,方便Socket.io复用:
// session.js "use strict"; const session = require("express-session"); const MongoStore = require("connect-mongo")(session); const config = require("../config"); const db = require("../db"); // 单独创建Store实例 const sessionStore = new MongoStore({ mongooseConnection: db.Mongoose.connection, }); // 导出Session中间件和Store if (process.env.NODE_ENV === "production") { module.exports = { session: session({ secret: config.sessionSecret, resave: false, saveUninitialized: false, store: sessionStore, }), store: sessionStore }; } else { module.exports = { session: session({ secret: config.sessionSecret, resave: false, saveUninitialized: true, store: sessionStore, }), store: sessionStore }; }
问题2:Passport.socketio的配置修正
现在调整你的ioServer代码,正确引用Session Store,同时确保Cookie的key和Express Session配置一致:
// ioServer.js let ioServer = (app, cookieParser) => { app.locals.chatrooms = []; const config = require("./config"); const server = require("http").Server(app); const io = require("socket.io")(server); const passportSocketIo = require("passport.socketio"); // 现在我们可以正确获取Store实例 const { store: sessionStore } = require("./session"); const helper = require("./helpers"); io.use( passportSocketIo.authorize({ cookieParser: cookieParser, key: "connect.sid", // 确保和Express Session的name参数一致(默认就是connect.sid) secret: config.sessionSecret, // 和Express Session的secret完全一致 store: sessionStore, // 使用单独抽出来的Store实例 success: helper.onAuthorizeSuccess, fail: helper.onAuthorizeFail, }) ); const socket = require("./socket"); socket(io, app); return server; };
问题3:检查Passport的序列化/反序列化
如果上面的修改后还是无法获取socket.request.user,那大概率是Passport的序列化和反序列化逻辑有问题。确保你有类似下面的代码:
// passport.js(示例) passport.serializeUser((user, done) => { // 把用户ID存入Session done(null, user.id); }); passport.deserializeUser((id, done) => { // 根据ID从数据库获取用户对象 User.findById(id, (err, user) => { done(err, user); }); });
这一步是Passport将Session中的passport.user(也就是用户ID)转换成完整的user对象的关键,如果这步缺失或错误,socket.request.user就会是undefined。
问题4:Express中间件顺序验证
确保你的Express中间件挂载顺序正确,顺序错误会导致Session或Passport无法正常工作:
// server.js app.use(ChatCAT.session); // 先挂载Session app.use(passport.initialize()); // 再初始化Passport app.use(passport.session()); // 然后挂载Passport Session app.use("/", ChatCAT.router); // 最后挂载路由
验证修改
完成上面的修改后,在Socket连接的回调里打印socket.request.user,应该就能看到完整的用户对象了,然后你就可以通过socket.request.user.id获取用户ID:
// socket.js io.of("/chatter").on("connection", (socket) => { console.log("Authenticated user:", socket.request.user); socket.on("join", (data) => { const userID = socket.request.user?.id || ""; // 后续逻辑... }); });
内容的提问来源于stack exchange,提问作者Zia

