【发布时间】:2017-05-30 05:55:12
【问题描述】:
首先,我知道在我之前已经多次问过同样的问题,但我在 StackOverflow 上找到的任何问题都找不到答案。
我最近刚开始学习express,我第一次尝试创建应用程序,无论是后端还是前端
javascript 库(来自PHPworld)。我已经声明了一个 MongoDB 模型架构,其中包含一些前期工作和一个将输入的密码与
存储在数据库中的散列密码。除了 comparePassword 方法从不返回匹配的密码之外,其他一切似乎都可以正常工作。
我使用bcryptjs 库进行密码哈希和比较,使用passport 库进行身份验证。
用户模型 (models/user.js):
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
bcrypt = require('bcryptjs');
SALT_WORK_FACTOR = 10;
var userSchema = new Schema({
//id: ObjectId,
email: {
type: String,
unique: true,
required: true
},
name: {
type: String,
required: true
},
password: {
type: String,
required: true
}
});
userSchema.pre('save', function(next) { // Hash the password before adding it to the database
var user = this;
// only hash the password if it has been modified (or is new)
if (!user.isModified('password')) return next();
// generate a salt
bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt) {
if (err) return next(err);
// hash the password using our new salt
bcrypt.hash(user.password, salt, function(err, hash) {
if (err) return next(err);
// override the cleartext password with the hashed one
user.password = hash;
next();
});
});
});
userSchema.methods.comparePassword = function(candidatePassword, cb) {
var user = this;
bcrypt.compare(candidatePassword, user.password, function(err, isMatch) {
console.log(candidatePassword);
console.log(user.password);
console.log((candidatePassword === user.password) ? 'passwords match' : 'passwords dont match' );
return;
if (err) return cb(null, err);
cb(null, isMatch);
});
};
module.exports = mongoose.model('User', userSchema);
身份验证策略 (config/passport.js):
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var mongoose = require('mongoose');
var User = mongoose.model('User');
passport.use(new LocalStrategy({
usernameField: 'email'
},
function(username, password, done) {
User.findOne({ email: username }, function (err, user) {
if (err) { return done(err); }
if (!user) { // Return if user not found in database
return done(null, false, {
message: 'User not found'
});
}
// It will always output "Incorrect creditentials"
if (!user.comparePassword(password)) {
return done(null, false, {
error: true,
message: 'Incorrect creditentials'
});
}
return done(null, user); // If credentials are correct, return the user object
});
}
));
最后,我的登录路径 (routes/auth.js):
var router = require('express').Router(); // get router instance
var request = require('request');
var passport = require('passport');
var User = require('../../models/user');
var tokenAuth = require('../../middlewares/token');
router.post('/signin', function(req, res) {
passport.authenticate('local', function(err, user, info){
var token;
if (err) { // If Passport throws/catches an error
res.status(404).json(err);
return;
}
if(user) { // If a user is found
token = user.generateJwt();
res.status(200);
res.json({
"token" : token
});
} else {
// If user is not found
res.status(401).json(info);
}
})(req, res);
});
module.exports = router;
编辑:
如果我删除 console.log 的输出:
bcrypt.compare(candidatePassword, user.password, function(err, isMatch) {
console.log(candidatePassword);
console.log(user.password);
console.log((candidatePassword === user.password) ? 'passwords match' : 'passwords dont match' );
return;
if (err) return cb(null, err);
cb(null, isMatch);
});
};
并尝试执行回调函数,我会得到以下错误:
cb(null, isMatch);
^
TypeError: undefined is not a function
at D:\project\backend\dist\models\user.js:51:9
at D:\project\node_modules\bcryptjs\dist\bcrypt.js:297:21
at D:\project\node_modules\bcryptjs\dist\bcrypt.js:1250:21
at Object.next [as _onImmediate] (D:\project\node_modules\bcryptjs\dist\bcrypt.js:1130:21)
at processImmediate [as _immediateCallback] (timers.js:354:15)
编辑 2:
所以,我终于能够比较密码并且能够console.log 密码是否匹配。我能够通过 Promises 实现这一目标。现在我不确定如何将该 Promise 传递给 passport 处理程序,以便它可以返回路由的用户结果。
这是comparePassword 方法:
userSchema.methods.comparePassword = function(candidatePassword) {
var user = this;
return new Promise(function(resolve,reject)
{
bcrypt.compare(candidatePassword, user.password, function (err, isMatch) {
// Prevent conflict btween err and isMatch
if (err)
reject(new Error("Error checking use password"));
else
console.log(isMatch === true ? 'passwords match' : 'passwords dont match');
return;
resolve(isMatch);
});
});
};
还有passport.js:
passport.use(new LocalStrategy({
usernameField: 'email'
},
function(username, password, done) {
User.findOne({ email: username }, function (err, user) {
if (err) { return done(err); }
// Return if user not found in database
user.comparePassword(password).then(function(isMatch) {
return isMatch === true ? user : null; // How to pass the user object to route??
}).catch(function (err) { // handle possible errors
return done(err);
})
});
}
));
【问题讨论】:
标签: javascript mongodb express bcrypt mongoose-schema