GraphQL与Passport Session:查询时无法访问req.user问题咨询
我之前也碰到过一模一样的问题!Passport的session配置很容易踩坑,尤其是和GraphQL搭在一起的时候,咱们一步步来排查:
第一步:检查Passport Session的基础配置有没有漏
Passport Session依赖express-session,而且挂载顺序绝对不能错:
- 先启用express-session,要在Passport初始化之前:
const session = require('express-session'); app.use(session({ secret: '你的密钥(生产环境别明文写!)', resave: false, saveUninitialized: false, // 开发环境用内存存储没问题,生产环境记得换Redis这类持久化存储 })); - 然后必须调用
passport.session(),而且要放在passport.initialize()之后:app.use(passport.initialize()); app.use(passport.session()); // 这步忘写的话,会话完全不会生效!
第二步:确认serializeUser和deserializeUser实现正确
这俩是Passport会话的核心,负责把用户信息存进会话、从会话里取出来:
// 只把用户唯一标识(比如ID)存到会话里,别存整个用户对象 passport.serializeUser((user, done) => { done(null, user.id); }); // 从会话里的ID还原出完整用户对象 passport.deserializeUser(async (id, done) => { try { const user = await User.findById(id); // 换成你项目里的用户查询逻辑 done(null, user); } catch (err) { done(err); } });
要是这俩函数写错了(比如serializeUser传了错误的标识,或者deserializeUser查不到用户),
req.user肯定拿不到!
第三步:GraphQL上下文必须传入req对象
GraphQL解析器默认拿不到req,得手动把它传到上下文里:
如果你用的是Apollo Server,配置要这样写:
const server = new ApolloServer({ typeDefs, resolvers, context: ({ req }) => ({ req }), // 把req注入上下文 // 注意:Apollo Server要挂载在session和passport中间件之后! });
然后在解析器里就能通过上下文访问req.user了:
const resolvers = { Query: { currentUser: (parent, args, { req }) => { return req.user; // 现在应该能拿到登录用户了! }, }, };
要是用的是
express-graphql,也要确保把req传递给解析器的context参数。
第四步:登录请求的处理要正确
如果是用GraphQL Mutation做登录,别忘记手动调用req.login()——有时候LocalStrategy成功后会自动调用,但手动处理时必须加这步:
Mutation: { login: async (parent, { username, password }, { req }) => { return new Promise((resolve, reject) => { passport.authenticate('local', (err, user) => { if (err || !user) return reject(err); // 手动触发Passport的会话存储逻辑 req.login(user, (err) => { if (err) return reject(err); resolve(user); }); })(req); }); }, },
如果前端和服务器是跨域的(比如前端在localhost:3000,服务器在localhost:4000),还要解决Cookie的传递问题:
- 服务器端CORS要允许携带凭证:
const cors = require('cors'); app.use(cors({ origin: 'http://localhost:3000', // 你的前端地址 credentials: true, // 必须设为true,Cookie才会被传递 })); - 前端请求也要带上凭证,比如Apollo Client的配置:
const client = new ApolloClient({ uri: 'http://localhost:4000/graphql', cache: new InMemoryCache(), credentials: 'include', // 告诉浏览器携带Cookie });
开发环境跨域的话,session的Cookie可以临时把
sameSite设为'none',同时开启secure: true(需要用https,本地可以用ngrok或者开启本地https服务)。
内容的提问来源于stack exchange,提问作者Lisa Schmitz
相关产品推荐
相关产品推荐

