You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js Express登录表单验证错误排查与修复求助

问题排查与修复方案

你的登录逻辑存在两个核心问题,导致无论凭据正确与否都提示错误:

1. 用户存在性判断逻辑错误

mysql模块的query方法即使未查询到数据,返回的results也是空数组而非null/undefined,因此!results的判断永远不成立。当输入不存在的邮箱时,results[0]为undefined,此时调用bcrypt.compare(password, results[0].password)会因第二个参数为undefined直接返回false,触发错误提示。

2. 未处理数据库查询异常

db.query的回调中未处理error参数,若数据库查询出现异常(如连接失败、SQL语法错误),会直接跳过后续逻辑,但不会触发外层try/catch(回调函数不在try的同步执行栈内),导致错误被隐藏。


修改后的login函数代码

exports.login = async (req, res) => {
  try {
    const { email, password } = req.body;

    if (!email || !password) {
      return res.status(400).render('login', {
        message: '请输入邮箱和密码'
      })
    }

    db.query('SELECT * FROM users WHERE email = ?', [email], async (error, results) => {
      // 优先处理数据库查询错误
      if (error) {
        console.error('数据库查询错误:', error);
        return res.status(500).render('login', {
          message: '服务器内部错误'
        });
      }

      // 判断用户是否存在
      if (results.length === 0) {
        return res.status(401).render('login', {
          message: '邮箱或密码错误'
        });
      }

      // 仅当用户存在时,执行密码对比
      const isPasswordValid = await bcrypt.compare(password, results[0].password);
      if (!isPasswordValid) {
        return res.status(401).render('login', {
          message: '邮箱或密码错误'
        });
      }

      // 密码验证通过,生成JWT并设置Cookie
      const id = results[0].id;
      const token = jwt.sign({ id }, process.env.JWT_SECRET, {
        expiresIn: process.env.JWT_EXPIRES_IN
      });

      console.log("生成的Token:", token);

      const cookieOptions = {
        expires: new Date(
          Date.now() + process.env.JWT_COOKIE_EXPIRES * 24 * 60 * 60 * 1000
        ),
        httpOnly: true
      };

      res.cookie('jwt', token, cookieOptions);
      res.status(200).redirect("/");
    });

  } catch (error) {
    console.error('登录逻辑异常:', error);
    res.status(500).render('login', {
      message: '服务器内部错误'
    });
  }
}

额外优化建议

  1. 统一错误提示:避免区分“邮箱不存在”和“密码错误”,防止恶意用户枚举有效邮箱。
  2. Promise化数据库操作:用util.promisify将mysql的回调API转为Promise,配合async/await消除回调嵌套,让逻辑更连贯。
  3. 提升密码哈希强度:注册时bcrypt.hash(password, 8)的盐轮数可提高到10-12,在可接受的性能损耗范围内增强密码安全性。

内容的提问来源于stack exchange,提问作者tehkum

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 13:21:24