Node.js中无法在函数外部获取用户token的问题求助
解决Node.js+Mongoose+GraphQL登录流程中无法获取Token的问题
你的核心问题是异步回调导致的变量作用域和执行顺序问题:
getAuthenticated和comparePassword采用回调式异步逻辑,但Resolver里的同步代码会先于回调执行,导致外部token变量还没被赋值就返回了。- 你给
getAuthenticated加了async关键字,但内部还是用回调,并没有返回Promise,所以调用.then()会得到undefined。
以下是具体的修复方案:
1. 重构comparePassword为Promise风格
把回调式的密码比对改成返回Promise,方便后续用await处理:
UserSchema.methods.comparePassword = function(candidatePassword) { return new Promise((resolve, reject) => { bcrypt.compare(candidatePassword, this.password, (err, isMatch) => { if (err) return reject(err); resolve(isMatch); }); }); };
2. 重构getAuthenticated方法,移除回调并返回Promise
完全用async/await重写,去掉回调参数,直接返回用户实例或抛出错误:
UserSchema.statics.getAuthenticated = async function(email, password) { // 查找用户 const user = await this.findOne({ email }); if (!user) throw new Error('用户不存在'); // 比对密码 const isMatch = await user.comparePassword(password); if (!isMatch) throw new Error('密码错误'); // 处理登录尝试次数和锁定状态 if (user.loginAttempts || user.lockUntil) { await user.updateOne({ $set: { loginAttempts: 0 }, $unset: { lockUntil: 1 } }); } return user; };
3. 修改登录Resolver,正确使用await获取用户并生成Token
现在可以在Resolver里以同步风格处理异步逻辑,确保Token能正确赋值:
login: async (_, { email, password }) => { try { // 等待用户认证完成 const user = await User.getAuthenticated(email, password); // 生成Token const token = user.createToken(); return { token }; } catch (error) { // 可根据错误类型返回对应GraphQL错误 throw new Error(error.message); } },
额外可选方案
如果你不想修改原有方法,也可以用Node.js内置的util.promisify把回调函数转换成Promise:
const { promisify } = require('util'); const getAuthenticatedAsync = promisify(User.getAuthenticated); // 在Resolver里使用:const user = await getAuthenticatedAsync(email, password)
但直接重构为Promise+async/await的代码可读性更高,更符合现代Node.js开发规范。
内容的提问来源于stack exchange,提问作者pelotador.1
相关产品推荐
相关产品推荐

