【问题标题】:sequelize promise always return false续集承诺总是返回假
【发布时间】:2021-02-15 20:11:37
【问题描述】:

我正在创建一个 react-native 应用程序。

流程是这样的,客户必须输入电子邮件和密码才能注册,数据将保存在数据库中。在保存数据之前,我使用了 pre-hook beforeValidate 来使用 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,
      allowNull: false
    },
    password : {
      type: Sequelize.STRING,
      allowNull: false
    },
    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 文件的 sn-p,如下所示:

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.无效的电子邮件或密码”错误。任何形式的帮助表示赞赏。谢谢。

【问题讨论】:

  • catcherr的值是多少?
  • 另外,bcrypt 提供了一个 promise api。您不需要使用 Sync 函数或创建新的 Promise
  • @Matt 它在邮递员上返回“错误”:“2.无效的电子邮件或密码!”`
  • 我指的是catch作用域中的err变量。
  • @Matt 对不起,我也很困惑。从上面的代码中,我无法准确指出错误是什么。是拒绝(错误)还是拒绝(假)?但我在错误上做了一个 console.log,上面写着TypeError: customer.comparePassword is not a function

标签: node.js sequelize.js bcrypt


【解决方案1】:

我创建了一个函数(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' });
}

【讨论】:

  • 嘿,@Matt 我已经根据 SkylarClark 在评论中提到的错误更新了我的答案
  • 酷。正如我在另一个线程中提到的,该函数可以通过Customer.prototype.comparePassword 在sequelilze 模型中定义,以模拟OPs 代码。
  • 如果你把它设为async 函数并使用bcrypt.compare() 它不会阻塞JS事件循环
  • 谢谢@Arya 我已经使用了代码并且它有效!我现在正在尝试在我的 Customer 模型中使用该函数来探索更多内容。
【解决方案2】:

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'});
  }
});

【讨论】:

  • 谢谢!我仍在学习 sequelize,但较新版本的文档有点难找。这有助于我以其他方式使用 sequelize 模型。
猜你喜欢
  • 2021-11-27
  • 2019-05-27
  • 2014-04-23
  • 1970-01-01
  • 2016-06-15
相关资源
最近更新 更多