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

bcrypt.compare对比密码始终返回false的问题求助

bcrypt.compare始终返回false,登录验证失败问题排查

我遇到了bcrypt.compare突然失效的问题,调用后doMatch始终返回false。目前可以正常创建带哈希密码的新用户,但无法完成登录。

登录控制器代码

const postLoginController = async (req, res) => {
  const email = req.body.email;
  const password = req.body.password;
  try {
    User.findOne({ email: email }).then((user) => {
      console.log('password, user.password', password, user.password);
      bcrypt.compare(password, user.password).then((doMatch) => {
        console.log('doMatch', doMatch);
        //Comparing the password the user entered with the password stored in the db
        if (doMatch) {
          console.log('passwords match');
          req.session.isLoggedIn = true;
          req.session.user = user;
          req.session.save();
          res.status(200).json({ isLoggedIn: true, message: 'Logged in!' });
        } else {
          res
            .status(401)
            .json({ isLoggedIn: false, message: 'Invalid credentials. Please try again.' });
        }
      });
    });
  } catch (err) {
    res.status(400).json({ error: 'Failed to login.' });
  }
};

控制台输出

password, user.password 123456 $2a$12$9YqCOmycoiLJ8uf7HfL4HebR2hHrJ7b2e6YspG7cP8.6UeAbapHEm

注册控制器代码

const postSignupController = async (req, res) => {
  const email = req.body.email;
  const password = req.body.password;
  try {
    User.findOne({ email: email }).then((userDoc) => {
      if (userDoc) {
        res.status(409).json({ isLoggedIn: false, message: 'The user already exists.' });
        return;
      } else {
        res.status(200).json({ isLoggedIn: true, message: 'Signed up' });
        return bcrypt.hash(password, 12).then((hashedPassword) => {
          const user = new User({
            email: email,
            password: hashedPassword,
            cart: { items: [] },
          });
          return user.save();
        });
      }
    });
  } catch (err) {
    res.status(400).json({ error: 'Failed to sign up.' });
  }
};

问题原因

核心问题出在注册控制器的响应时机错误:你在生成哈希密码并保存用户之前,就提前返回了res.status(200).json(...)。Node.js中响应发送后,后续的异步操作(哈希生成、用户保存)可能会被中断或执行异常,导致数据库中存储的密码并非正确的哈希值(甚至可能是空值或不完整内容),最终登录时bcrypt对比自然失败。

解决方案

1. 调整注册控制器的响应时机

将成功响应移到用户保存完成之后,确保哈希密码正确写入数据库:

const postSignupController = async (req, res) => {
  const email = req.body.email;
  const password = req.body.password;
  try {
    User.findOne({ email: email }).then((userDoc) => {
      if (userDoc) {
        return res.status(409).json({ isLoggedIn: false, message: '该用户已存在。' });
      } 
      // 先处理哈希和用户保存,再返回响应
      bcrypt.hash(password, 12).then((hashedPassword) => {
        const user = new User({
          email: email,
          password: hashedPassword,
          cart: { items: [] },
        });
        return user.save().then(() => {
          res.status(200).json({ isLoggedIn: true, message: '注册成功' });
        });
      }).catch(err => {
        res.status(400).json({ error: '注册失败。' });
      });
    }).catch(err => {
      res.status(400).json({ error: '注册失败。' });
    });
  } catch (err) {
    res.status(400).json({ error: '注册失败。' });
  }
};

2. 优化代码:使用async/await替代then链

统一用async/await能让代码更清晰,也更易处理错误:

// 优化后的注册控制器
const postSignupController = async (req, res) => {
  try {
    const { email, password } = req.body;
    const existingUser = await User.findOne({ email });
    if (existingUser) {
      return res.status(409).json({ isLoggedIn: false, message: '该用户已存在。' });
    }
    const hashedPassword = await bcrypt.hash(password, 12);
    const user = new User({
      email,
      password: hashedPassword,
      cart: { items: [] },
    });
    await user.save();
    res.status(200).json({ isLoggedIn: true, message: '注册成功' });
  } catch (err) {
    res.status(400).json({ error: '注册失败。' });
  }
};

// 优化后的登录控制器
const postLoginController = async (req, res) => {
  try {
    const { email, password } = req.body;
    const user = await User.findOne({ email });
    if (!user) {
      return res.status(401).json({ isLoggedIn: false, message: '无效的登录凭证,请重试。' });
    }
    const doMatch = await bcrypt.compare(password, user.password);
    if (doMatch) {
      req.session.isLoggedIn = true;
      req.session.user = user;
      await req.session.save();
      return res.status(200).json({ isLoggedIn: true, message: '登录成功!' });
    }
    res.status(401).json({ isLoggedIn: false, message: '无效的登录凭证,请重试。' });
  } catch (err) {
    res.status(400).json({ error: '登录失败。' });
  }
};

3. 额外排查点

  • 检查数据库password字段类型:确保是String类型,且长度至少设置为60(bcrypt哈希固定为60字符),避免字段长度不足导致哈希被截断。
  • 处理密码空格:在登录和注册时对密码做trim()处理,比如const password = req.body.password.trim();,防止用户输入时不小心带入空格引发验证失败。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 18:21:11