Node.js Mongoose create()在异步中间件完成之前解析

Node.js Mongoose create()在异步中间件完成之前解析,node.js,express,mongoose,Node.js,Express,Mongoose,我把这叫做控制器: var mongoose = require('mongoose'); var bcrypt = require('bcrypt-nodejs'); var UserSchema = new mongoose.Schema({ email: { type: string, unique: true, required: true, trim: true }, password: { type: string, r

我把这叫做控制器:

var mongoose = require('mongoose');

var bcrypt = require('bcrypt-nodejs');

var UserSchema = new mongoose.Schema({
  email: {
    type: string,
    unique: true,
    required: true,
    trim: true
  },
  password: {
    type: string,
    required: true
  },
    authtokens: {
        type: [{ type: mongoose.Schema.Types.ObjectId, ref: 'AuthToken' }]
    }
});

//hashing a password before saving it to the database
UserSchema.pre('save', function (next) {
    if (this.isNew) {
        bcrypt.gensalt(10, function(err, salt) {
            if (err) return next(err);
            bcrypt.hash(this.password, salt, null, function (err, hash){
                if (err) return next(err);
                this.password = hash;
                console.log('user.password ', this.password);
                next();
            });
        });
    } else next();
});
当通过电子邮件调用
createUser
时user@email.com,password
password
,我得到输出:

'use strict';

var mongoose = require('mongoose'),
    User = mongoose.model('User'),
    AuthToken = mongoose.model('AuthToken');

exports.createUser = function(req, res, next) {
    if (req.body.email && req.body.password && req.body.passwordConf) {
        var userData = {
            email: req.body.email,
            password: req.body.password,
            passwordConf: req.body.passwordConf
        };
        //use schema.create to insert data into the db
        User.create(userData, function (err, user) {
            console.log('user created ', user.password);
            if (err) {
                return next(err);
            } else {
                return res.redirect('/profile');
            }
        });
    } else {
        var err = new Error("Missing parameters");
        err.status = 400;
        next(err);
    }
};
另外,直接查看数据库,我看到这个用户使用纯文本密码->
password


为什么用户在数据库中有明文密码。我如何存储散列呢?

简而言之,您忘记了要进入一个具有不同功能范围的回调,并且您仍然引用了
这个
,它在当时实际上不是“model”实例

要更正此问题,请先复制一份
this
,然后再执行类似于使用回调启动另一个函数的操作:

user.password  $2a$10$wO.6TPUm5b1j6lvHdCi/JOTeEXHWhYernWU.ZzA3hfYhyWoOeugcq
user created  password
当然,另一种方法是使事情现代化,并将
Promise
结果与
async/await
一起使用。实际上是“核心”而不是分叉的库可以直接执行以下操作:

UserSchema.pre('save', function(next) {
  var user = this;              // keep a copy
  if (this.isNew) {
    bcrypt.genSalt(10, function(err,salt) {
      if (err) next(err);
      bcrypt.hash(user.password, salt, null, function(err, hash) {
        if (err) next(err);
        user.password = hash;
        next();
      });
    });
  }
});
除了现代方法通常是更干净的代码外,您也不需要更改
this
的范围,因为我们不会“深入”到另一个函数调用。所有内容都在同一个范围内更改,当然,在继续之前会等待异步调用

完整示例-回调 完整示例-承诺异步/等待 两者都显示正确加密的密码,因为我们实际上在模型实例中设置了值:

const { Schema } = mongoose = require('mongoose');
const bcrypt = require('bcrypt');

const uri = 'mongodb://localhost/crypto';

var userSchema = new Schema({
  email: String,
  password: String
});

userSchema.pre('save', async function() {
  if (this.isNew) {
    let salt = await bcrypt.genSalt(10);
    let hash = await bcrypt.hash(this.password, salt);
    this.password = hash;
  }
});

const log = data => console.log(JSON.stringify(data, undefined, 2));

const User = mongoose.model('User', userSchema);

(async function() {

  try {

    const conn = await mongoose.connect(uri);

    await Promise.all(Object.entries(conn.models).map(([k,m]) => m.remove()));

    await User.create({ email: 'ted@example.com', password: 'password' });

    let result = await User.findOne();
    log(result);

  } catch(e) {
    console.error(e)
  } finally {
    process.exit()
  }


})()
const { Schema } = mongoose = require('mongoose');
const bcrypt = require('bcrypt-nodejs');

const uri = 'mongodb://localhost/crypto';

var userSchema = new Schema({
  email: String,
  password: String
});

userSchema.pre('save', function(next) {
  var user = this;          // keep a copy
  if (this.isNew) {
    bcrypt.genSalt(10, function(err,salt) {
      if (err) next(err);
      bcrypt.hash(user.password, salt, null, function(err, hash) {
        if (err) next(err);
        user.password = hash;
        next();
      });
    });
  }
});

const log = data => console.log(JSON.stringify(data, undefined, 2));

const User = mongoose.model('User', userSchema);

(async function() {

  try {

    const conn = await mongoose.connect(uri);

    await Promise.all(Object.entries(conn.models).map(([k,m]) => m.remove()));

    await User.create({ email: 'ted@example.com', password: 'password' });

    let result = await User.findOne();
    log(result);

  } catch(e) {
    console.error(e)
  } finally {
    process.exit()
  }


})()
const { Schema } = mongoose = require('mongoose');
const bcrypt = require('bcrypt');

const uri = 'mongodb://localhost/crypto';

var userSchema = new Schema({
  email: String,
  password: String
});

userSchema.pre('save', async function() {
  if (this.isNew) {
    let salt = await bcrypt.genSalt(10);
    let hash = await bcrypt.hash(this.password, salt);
    this.password = hash;
  }
});

const log = data => console.log(JSON.stringify(data, undefined, 2));

const User = mongoose.model('User', userSchema);

(async function() {

  try {

    const conn = await mongoose.connect(uri);

    await Promise.all(Object.entries(conn.models).map(([k,m]) => m.remove()));

    await User.create({ email: 'ted@example.com', password: 'password' });

    let result = await User.findOne();
    log(result);

  } catch(e) {
    console.error(e)
  } finally {
    process.exit()
  }


})()
{
  "_id": "5aec65f4853eed12050db4d9",
  "email": "ted@example.com",
  "password": "$2b$10$qAovc0m0VtmtpLg7CRZmcOXPDNi.2WbPjSFkfxSUqh8Pu5lyN4p7G",
  "__v": 0
}