Javascript 使用bcryptjs比较哈希和密码返回false

Javascript 使用bcryptjs比较哈希和密码返回false,javascript,node.js,express,Javascript,Node.js,Express,我有通过电子邮件/updatePasswordViaEmail重置密码的终点 它工作得很好,它找到用户,我对密码进行哈希运算,我的问题是,当我在登录时进行比较时,它返回false。 我使用bcryptjs// const bcrypt = require("bcryptjs"); 我的盐轮是: const BCRYPT_SALT_ROUNDS = 8; 这是我的终点 router.put('/users/updatePasswordViaEmail', (req, res) =>

我有通过电子邮件/updatePasswordViaEmail重置密码的终点 它工作得很好,它找到用户,我对密码进行哈希运算,我的问题是,当我在登录时进行比较时,它返回false。 我使用bcryptjs//

const bcrypt = require("bcryptjs");
我的盐轮是:

const BCRYPT_SALT_ROUNDS = 8;
这是我的终点

    router.put('/users/updatePasswordViaEmail', (req, res) => {
      User.findOne({
        email: req.body.email,
        resetPasswordToken: req.body.resetPasswordToken,
        resetPasswordExpires: {
          $gt: Date.now(),
        },
      }).then(user => {
        console.log(user);
        if (user == null) {
          console.error('password reset link is invalid or has expired');
          res.status(403).send('password reset link is invalid or has expired');
        } else if (user != null) {
          console.log('user exists in db');
          bcrypt.hash(req.body.password, BCRYPT_SALT_ROUNDS).then(hashedPassword => {
            console.log(hashedPassword);
            user.password = hashedPassword;
            user.resetPasswordToken = null;
            user.resetPasswordExpires = null;
            user.save(function (err) {
              if (err) {
                console.error('ERROR!');
              }
            });
          }).then(() => {
            console.log('password updated');
            res.status(200).send({message: 'password updated'});
          });
        } else {
          console.error('no user exists in db to update');
          res.status(401).json('no user exists in db to update');
        }
      });
    });
这是我的预存

    userSchema.pre('save', async function (next) {
      // Hash the password before saving the user model
      const user = this;

      if (user.isModified("password") || user.isNew) {
        //Perform password hashing here
        user.password = await bcrypt.hash(user.password, BCRYPT_SALT_ROUNDS)
      } else {
        return next();
      }
    });
在这里,当我尝试查看密码是否匹配时,它总是返回false:

    userSchema.statics.findByCredentials = async (email, password) => {
      // Search for a user by email and password.
      const user = await User.findOne({email});
      if (!user) {
        throw new MyError({error: 'Invalid login credentials'})
      }
      const isPasswordMatch = await bcrypt.compare(password, user.password);
      console.log(isPasswordMatch)// only comes false
      if (!isPasswordMatch) {
        throw new MyError({error: 'Invalid login credentials'})
      }
      return user
    };
我的整个用户模型:

const mongoose = require('mongoose');
const bcrypt = require("bcryptjs");

const jwt = require('jsonwebtoken');
const uniqueValidator = require('mongoose-unique-validator');
const BCRYPT_SALT_ROUNDS = 8;

// Get the Schema constructor
const Schema = mongoose.Schema;

function MyError(message) {
  this.message = message
}

MyError.prototype = new Error();

const userSchema = new Schema({
  name: {
    type: String,
    required: true,
    trim: true
  },
  email: {
    type: String,
    required: true,
    unique: true
  },
  password: {
    type: String,
  },
  tokens: [{
    token: {
      type: String,
      required: true
    }
  }],
  resetPasswordToken: {
    type: String,
  },
  resetPasswordExpires: Date,

  userRooms: [{type: Schema.Types.ObjectId, ref: 'Room'}]
});

userSchema.pre('save', async function (next) {
  // Hash the password before saving the user model
  const user = this;

  if (user.isModified("password") || user.isNew) {
    //Perform password hashing here
    user.password = await bcrypt.hash(user.password, BCRYPT_SALT_ROUNDS)
  } else {
    return next();
  }
});

userSchema.methods.generateAuthToken = async function () {
  // Generate an auth token for the user
  const user = this;
  const token = jwt.sign({_id: this._id, isAdmin: this.isAdmin}, "Stack", {

    expiresIn: '1d' // expires in 365 days

  }, process.env.JWT_KEY); //get the private key from the config file -> environment variable
  console.log(token);
  user.tokens = user.tokens.concat({token});
  await user.save();
  return token
};

userSchema.statics.findByCredentials = async (email, password) => {
  // Search for a user by email and password.
  const user = await User.findOne({email});
  if (!user) {
    throw new MyError({error: 'Invalid login credentials'})
  }
  const isPasswordMatch = await bcrypt.compare(password, user.password);
  console.log(isPasswordMatch)// only comes false
  if (!isPasswordMatch) {
    throw new MyError({error: 'Invalid login credentials'})
  }
  return user
};

const User = mongoose.model('User', userSchema.plugin(uniqueValidator, {message: ''}));

module.exports = User;
解决方案:

我发现当我更新用户时,用户工作不正常,出现了一些问题,我将其更改为:

router.put('/users/updatePasswordViaEmail', async (req, res) => {
  const salt = await bcrypt.genSalt(10);
  const user = await User.findOne(
    {email: req.body.email},
    {resetPasswordToken: req.body.resetPasswordToken},
    {
      resetPasswordExpires: {
        $gt: Date.now(),
      }
    }
  );
  if (user == null) {
    console.error('password reset link is invalid or has expired');
    res.status(403).send('password reset link is invalid or has expired');
  } else if (user != null) {
    console.log('user exists in db');
    console.log(req.body.password);
    let hashedPassword = await bcrypt.hash(req.body.password, salt);
    const body = {
      password: hashedPassword,
      resetPasswordToken: null,
      resetPasswordExpires: null
    };
    let updatedUser = await User.findOneAndUpdate(req.body.email, body);
    console.log(updatedUser);
    console.log('password updated');
    res.status(200).send({message: 'password updated'});
  } else {
    console.error('no user exists in db to update');
    res.status(401).json('no user exists in db to update');
  }
});
router.post('/users/login', async (req, res) => {
  //Login a registered user
  try {
    const email = req.body.email;
    const password = req.body.password;
    const userData = await User.findOne({email});
    if (!userData) {
      throw new MyError({error: 'Invalid login credentials'})
    }
    // if ((user.isVerified)) {//todo verify user
    const isPasswordMatch = await bcrypt.compareSync(password, userData.password);
    console.log(isPasswordMatch);
    if (isPasswordMatch) {
      const token = await userData.generateAuthToken();
      let user = userData.toJSON();
      delete user.password;
      return res.send({user, token});
    } else return res.status(400).send({password: 'Wrong password'});
    // } else {
    //   return res.status(401).send({ msg: 'Account not verified' });
    // }
  } catch (e) {
    console.log(e);
  }
});
正如你所看到的,我使用findOneAndUpdate,它很有效

我将我的登录终点更改为:

router.put('/users/updatePasswordViaEmail', async (req, res) => {
  const salt = await bcrypt.genSalt(10);
  const user = await User.findOne(
    {email: req.body.email},
    {resetPasswordToken: req.body.resetPasswordToken},
    {
      resetPasswordExpires: {
        $gt: Date.now(),
      }
    }
  );
  if (user == null) {
    console.error('password reset link is invalid or has expired');
    res.status(403).send('password reset link is invalid or has expired');
  } else if (user != null) {
    console.log('user exists in db');
    console.log(req.body.password);
    let hashedPassword = await bcrypt.hash(req.body.password, salt);
    const body = {
      password: hashedPassword,
      resetPasswordToken: null,
      resetPasswordExpires: null
    };
    let updatedUser = await User.findOneAndUpdate(req.body.email, body);
    console.log(updatedUser);
    console.log('password updated');
    res.status(200).send({message: 'password updated'});
  } else {
    console.error('no user exists in db to update');
    res.status(401).json('no user exists in db to update');
  }
});
router.post('/users/login', async (req, res) => {
  //Login a registered user
  try {
    const email = req.body.email;
    const password = req.body.password;
    const userData = await User.findOne({email});
    if (!userData) {
      throw new MyError({error: 'Invalid login credentials'})
    }
    // if ((user.isVerified)) {//todo verify user
    const isPasswordMatch = await bcrypt.compareSync(password, userData.password);
    console.log(isPasswordMatch);
    if (isPasswordMatch) {
      const token = await userData.generateAuthToken();
      let user = userData.toJSON();
      delete user.password;
      return res.send({user, token});
    } else return res.status(400).send({password: 'Wrong password'});
    // } else {
    //   return res.status(401).send({ msg: 'Account not verified' });
    // }
  } catch (e) {
    console.log(e);
  }
});

如果你
console.log(user.password)
在那一点上,它是什么?@Ry-我得到一个像这样的散列密码:$2b$08$imb4no4vxcf8mjqijiuy9otnv7k3fo7txstvhi117ojtbgip/qooa,如果你
console.log(password)
在同一点上,它是什么?@Ry-它没有定义,所以它会给我一个错误。设置
user.password=hashedPassword
然后在
pre('save')
hook中再次对其进行散列的方式。让事情变得混乱的简单方法。我建议使用两个不同的属性,
user.password
user.hashedPassword
,如果您的ORM允许,只将
hashedPassword
保存到数据库中。(我不喜欢ORMs,所以也许有一种更典型的方式。)