pfr*_*ied 37 mongoose mongodb node.js
我正在寻找一种使用mongoose将帐户保存到MongoDB的好方法.
我的问题是:密码是异步散列的.一个二传手不会在这里工作,因为它只能同步工作.
我想到了两种方式:
创建模型的实例并将其保存在散列函数的回调中.
在'save'上创建一个预挂钩
这个问题有什么好的解决方案吗?
Noa*_*oah 111
mongodb博客有一篇很好的文章,详细介绍了如何实现用户身份验证.
http://blog.mongodb.org/post/32866457221/password-authentication-with-mongoose-part-1
以下链接直接从上面的链接复制:
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
bcrypt = require('bcrypt'),
SALT_WORK_FACTOR = 10;
var UserSchema = new Schema({
username: { type: String, required: true, index: { unique: true } },
password: { type: String, required: true }
});
UserSchema.pre('save', function(next) {
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) {
bcrypt.compare(candidatePassword, this.password, function(err, isMatch) {
if (err) return cb(err);
cb(null, isMatch);
});
};
module.exports = mongoose.model('User', UserSchema);
Run Code Online (Sandbox Code Playgroud)
var mongoose = require(mongoose),
User = require('./user-model');
var connStr = 'mongodb://localhost:27017/mongoose-bcrypt-test';
mongoose.connect(connStr, function(err) {
if (err) throw err;
console.log('Successfully connected to MongoDB');
});
// create a user a new user
var testUser = new User({
username: 'jmar777',
password: 'Password123';
});
// save user to database
testUser.save(function(err) {
if (err) throw err;
});
// fetch user and test password verification
User.findOne({ username: 'jmar777' }, function(err, user) {
if (err) throw err;
// test a matching password
user.comparePassword('Password123', function(err, isMatch) {
if (err) throw err;
console.log('Password123:', isMatch); // -> Password123: true
});
// test a failing password
user.comparePassword('123Password', function(err, isMatch) {
if (err) throw err;
console.log('123Password:', isMatch); // -> 123Password: false
});
});
Run Code Online (Sandbox Code Playgroud)
Soh*_*ail 18
对于那些愿意使用 ES6+ 语法的人可以使用这个 -
const bcrypt = require('bcryptjs');
const mongoose = require('mongoose');
const { isEmail } = require('validator');
const { Schema } = mongoose;
const SALT_WORK_FACTOR = 10;
const schema = new Schema({
email: {
type: String,
required: true,
validate: [isEmail, 'invalid email'],
createIndexes: { unique: true },
},
password: { type: String, required: true },
});
schema.pre('save', async function save(next) {
if (!this.isModified('password')) return next();
try {
const salt = await bcrypt.genSalt(SALT_WORK_FACTOR);
this.password = await bcrypt.hash(this.password, salt);
return next();
} catch (err) {
return next(err);
}
});
schema.methods.validatePassword = async function validatePassword(data) {
return bcrypt.compare(data, this.password);
};
const Model = mongoose.model('User', schema);
module.exports = Model;
Run Code Online (Sandbox Code Playgroud)
TL;DR - 打字稿解决方案
当我正在寻找相同的解决方案但使用打字稿时,我来到了这里。因此,对于对上述问题的 TS 解决方案感兴趣的任何人,以下是我最终使用的示例。
进口&& 内容:
import mongoose, { Document, Schema, HookNextFunction } from 'mongoose';
import bcrypt from 'bcryptjs';
const HASH_ROUNDS = 10;
Run Code Online (Sandbox Code Playgroud)
简单的用户界面和模式定义:
export interface IUser extends Document {
name: string;
email: string;
password: string;
validatePassword(password: string): boolean;
}
const userSchema = new Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
});
Run Code Online (Sandbox Code Playgroud)
用户模式预保存钩子实现
userSchema.pre('save', async function (next: HookNextFunction) {
// here we need to retype 'this' because by default it is
// of type Document from which the 'IUser' interface is inheriting
// but the Document does not know about our password property
const thisObj = this as IUser;
if (!this.isModified('password')) {
return next();
}
try {
const salt = await bcrypt.genSalt(HASH_ROUNDS);
thisObj.password = await bcrypt.hash(thisObj.password, salt);
return next();
} catch (e) {
return next(e);
}
});
Run Code Online (Sandbox Code Playgroud)
密码验证方法
userSchema.methods.validatePassword = async function (pass: string) {
return bcrypt.compare(pass, this.password);
};
Run Code Online (Sandbox Code Playgroud)
和默认导出
export default mongoose.model<IUser>('User', userSchema);
Run Code Online (Sandbox Code Playgroud)
注意:不要忘记安装类型包 ( @types/mongoose, @types/bcryptjs)