继承承诺总是返回false

问题描述

我正在创建一个本机应用程序。

该流程是这样的,客户必须输入电子邮件和密码来进行注册,数据将保存在数据库中。在保存数据之前,我已经使用了preValidate挂钩来使用bcrypt哈希密码。

直到这里,一切正常,但是当从instanceMethod comparePassword作出承诺时,我似乎无法返回true。

我有一个客户模型Customer.js文件,如下所示:

const Sequelize = require('sequelize');
const bcrypt = require('bcrypt');
const db = require('../config/database');

const Customer = db.define('customer',{
    id : {
      type: Sequelize.INTEGER,primaryKey: true,autoIncrement: true,allowNull: false
    },email : {
      type: Sequelize.STRING,unique: true,password : {
      type: Sequelize.STRING,createdAt : {
      type: Sequelize.Now
    },updatedAt : {
      type: Sequelize.Now
    }
  },{
    hooks: {
      afterValidate: (customer) => {
        customer.password = bcrypt.hashSync(customer.password,10);
      }
    },instanceMethods: {
      comparePassword: (candidatePassword) => {
        return new Promise((resolve,reject) => {
          bcrypt.compareSync(candidatePassword,this.password,(err,isMatch) => {
            if(err) {
              return reject(err);
            }
            if(!isMatch) {
              return reject(false);
            }
            resolve(true);
          });
        });
      }
    }
  });

module.exports = Customer;

和下面的authRoutes.js文件片段:

router.post('/login',async (req,res) => {
  const { email,password } = req.body;

  if ( !email || !password ) {
    return res.status(422).send({error: 'Must provide email and password!'});
  }

  const customer = await Customer.findOne({ where: {email} });

  if(!customer) {
    return res.status(422).send({error: '1. Invalid email or password!'});
  }

  try {
    await customer.comparePassword(password);
    const token = jwt.sign({ email },'MY_SECRET_KEY');
    res.send({ email,token });
  } catch(err) {
    return res.status(422).send({error: '2. Invalid email or password!'});
  }
});

没有任何错误,但即使输入了正确的凭据,它也始终会出现“ 2.无效的电子邮件或密码”错误。任何帮助都将受到赞赏。谢谢。

解决方法

我创建了一个函数(comparePassword)来比较密码和哈希密码,后者使用bcrypt来比较密码。

const bcrypt = require('bcryptjs');

const customer = await Customer.findOne({ where: { email } });
const comparePassword = (hashedPassword,password) => {
    return bcrypt.compareSync(password,hashedPassword);
};
try {
    if (!comparePassword(customer.password,password) {
        return res.status(422).send({ error: '2. Invalid email or password!' });
    }
    else {
        const token = jwt.sign({ email },'MY_SECRET_KEY');
        return res.status(200).send({ email,token });

    }
} catch (err) {
    console.log(err)
    return res.status(500).send({ error: 'something bad happened on server' });
}
,

Customer可以在Sequelize 4+中定义为类。然后可以将实例方法添加为常规类实例方法。

class Customer extends Sequelize.Model {

  static table_schema = {
    id: {
      type: Sequelize.INTEGER,primaryKey: true,autoIncrement: true,allowNull: false
    },...
  }

  static table_options = {
    ...
  }

  static init(sequelize){
    return super.init(this.table_schema,{ this.table_options,...sequelize })
  }

  static associate(models) {
    
  }

  async comparePassword(candidatePassword){
    return bcrypt.compare(candidatePassword,this.password)
  }

}

Customer.addHook('afterValidate',async function(customer){
  customer.password = await bcrypt.hash(customer.password,10);
})

然后,您应该能够在路由中使用异步comparePassword功能,类似于Arya's answer

router.post('/login',async (req,res) => {
  try {
    const { email,password } = req.body;

    if ( !email || !password ) {
      return res.status(422).send({error: 'Must provide email and password!'});
    }

    const customer = await Customer.findOne({ where: {email} });
    if (!customer) {
      console.log('Failed login [%s] not found',email)
      return res.status(422).send({error: 'Invalid email or password!'});
    }

    const auth = await customer.comparePassword(password);
    if (!auth) {
      console.log('Failed login [%s] bad password',email)
      return res.status(422).send({error: 'Invalid email or password!'});
    }

    const token = jwt.sign({ email },'MY_SECRET_KEY');
    res.send({ email,token });
  } 
  catch(err) {
    console.error('Failed to process request',err)
    return res.status(500).send({error: 'Internal Server Error'});
  }
});