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

登录端点存储哈希密码与用户输入密码比对失败求助

登录端点哈希密码比对失败问题排查与修复

问题概述

开发登录端点时,出现存储的哈希密码与用户输入密码比对失败的情况,无法正常授权用户。通过日志定位到代码在if (!passwordMatch)分支返回401错误,尝试直接比对或哈希输入密码均未解决问题。

问题根源

  1. signup端点中bcrypt回调与async/await混用:使用bcrypt的回调式API(genSalt、hash)嵌套在async函数中,可能导致哈希生成过程中的异常未被外层try/catch捕获,或执行流程出现意外,最终存储到数据库的密码哈希值不正确。
  2. login端点存在未声明变量与回调隐患:hashedPasswordFromDb未使用const/let声明,可能造成全局变量污染;同时回调式的bcrypt.compare也存在潜在的异步流程问题。

修复方案

1. 重构signup端点的密码哈希逻辑(改用async/await版本的bcrypt API)

将回调式的盐生成和密码哈希替换为Promise风格的async/await调用,确保错误能被正确捕获,代码逻辑更清晰:

// Signup endpoint
app.post('/signup', async (req, res) => {
    try {
      const { firstName, lastName, email, role, password } = req.body;

      const existingUser = await User.findOne({ email });
      if (existingUser) {
        return res.status(400).json({ message: 'Email already exists' });
      }

      let plainTextPassword = password;
      if (!plainTextPassword) {
        plainTextPassword = 'defaultPassword123';
      }

      // 改用async/await生成盐和哈希密码
      const salt = await bcrypt.genSalt(10);
      const hashedPassword = await bcrypt.hash(plainTextPassword, salt);

      const newUser = new User({
        firstName,
        lastName,
        email,
        role,
        password: hashedPassword,
      });

      await newUser.save();

      const token = jwt.sign({ email: newUser.email }, secretKey);
      const expirationDate = new Date().getTime() + 3600000;

      const user = {
        firstName: newUser.firstName,
        lastName: newUser.lastName,
        email: newUser.email,
        role: newUser.role,
        id: newUser._id,
        _token: token,
        _tokenExpirationDate: expirationDate,
      };

      const authResponse = new AuthResponseData(user);
      res.status(201).json(authResponse);
    } catch (error) {
      console.error(error);
      res.status(500).json({ message: 'Internal server error' });
    }
    console.log(req.body)
  });

2. 重构login端点的密码比对逻辑(改用async/await版本的bcrypt API)

替换回调式的bcrypt.compare为async/await调用,同时修复未声明的变量问题:

// Login endpoint
app.post('/login', async (req, res) => {
  try {
    const { email, password } = req.body;
    const userEmail = email;
    const userPassword = password;

    console.log(userEmail);
    console.log(userPassword);

    const user = await User.findOne({ email });
    if (!user) {
      return res.status(401).json({ message: 'Invalid email or password' });
    };

    console.log('user verified');
    console.log(user.password);
    console.log(userPassword);

    // 改用async/await比对密码
    const passwordMatch = await bcrypt.compare(userPassword, user.password);
    
    console.log(passwordMatch);
    if (!passwordMatch) {
      return res.status(401).json({ message: 'Invalid email or password' });
    }

    const token = jwt.sign({ email: user.email }, secretKey);
    const expirationDate = new Date().getTime() + 3600000;

    const loggedInUser = {
      firstName: user.firstName,
      lastName: user.lastName,
      email: user.email,
      role: user.role,
      id: user._id,
      _token: token,
      _tokenExpirationDate: expirationDate,
    };

    const authResponse = new AuthResponseData(loggedInUser);
    res.status(200).json(authResponse);

  } catch (error) {
    console.error('Error:', error);
    console.error('Stack trace:', error.stack);
    res.status(500).json({ message: 'Internal server error' });
  }
}); 

3. 验证数据库中的密码哈希值

检查MongoDBusers集合中用户的password字段,确保是符合bcrypt格式的哈希值(通常以$2b$开头,长度约60字符)。如果之前存储了错误的哈希值,需要重新注册用户,或手动更新密码为正确的哈希值。

验证修复效果

  1. 重启服务,重新注册测试用户。
  2. 使用该用户的邮箱和密码登录,确认能成功获取授权token。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 22:45:03