Node.js使用Sequelize、JWT、MySQL实现登录授权时密码一致却登录失败
代码问题梳理
1. findSalt函数错误处理逻辑异常
function findSalt (email) { return new Promise((resolve, reject) => { User.findOne({where: {email}}) .then(result => { resolve(result); }) .catch(err => { resolve(err); // 错误点:查询异常时应该reject而非resolve }); }) }
如果数据库查询抛出异常,错误对象会被正常resolve,后续调用createHash(password, doc.salt)时,doc是错误对象不存在salt属性,直接抛出异常进入全局catch,返回登录失败。
2. 用户校验分支未中断Promise链,导致重复发送响应
你在判断user == null时直接调用了res.json({msg: "failed"})然后return,此时return的是undefined,Promise链会继续执行后续的then:
.then((user) => { if (user == null) { res.json({msg: "failed"}); return; // 仅返回undefined,不会中断整个Promise链 } // 生成token逻辑 }) .then(token => { // 此时token为undefined,依然会执行这段逻辑 const parsedKey = 'access_' + email; return saveRedis(req, parsedKey, token, 60 * 5); }) .then((token) => { // 二次调用res.json会抛出「响应头已发送」的错误 res.cookie('accessToken', token, {secure: false, httpOnly: true,readOnly : true}); res.json({msg: 'success'}); }) .catch(err => { // 上述错误会进入catch分支,再次发送响应最终返回失败 res.json({msg: "failed", err}); });
这是密码哈希正确依旧登录失败的核心原因:第一次发送响应后,后续逻辑重复触发响应发送报错,进入全局catch。
3. 冗余Promise包装(非功能问题,可优化)
findUser和findSalt不需要手动封装Promise,Sequelize的查询方法本身就返回Promise,直接返回即可减少逻辑冗余。
修复方案
- 修正
findSalt的catch分支,改为reject(err) - 用户不存在时直接抛出错误中断Promise链:
.then((user) => { if (user == null) { throw new Error('账号或密码错误') } // 原有生成token的逻辑 })
- 确认
saveRedis函数返回值为传入的token,避免后续写入cookie的值错误。
内容的提问来源于stack exchange,提问作者zodol e
相关产品推荐
相关产品推荐

