| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 | const crypto = require('crypto')const mongoose = require('mongoose')mongoose.Promise = require('bluebird')var UserSchema = new mongoose.Schema({  name: String,  loginId: {    type: String,    lowercase: true,    required: true  },  role: {    type: String,    default: 'user'  },  password: {    type: String,    required: true  },  provider: String,  salt: String,  token: String})/** * Validations */// Validate empty emailUserSchema  .path('loginId')  .validate((loginId) => {    return loginId.length  }, '登陆名不能空')// Validate empty passwordUserSchema  .path('password')  .validate((password) => {    return password.length  }, '密码不能空')// Validate loginId is not takenUserSchema  .path('loginId')  .validate(function (value, respond) {    return this.constructor.findOne({ loginId: value }).exec()      .then(user => {        if (user) {          if (this.id === user.id) {            return respond(true)          }          return respond(false)        }        return respond(true)      })      .catch((err) => {        throw err      })  }, '该用户已存在')var validatePresenceOf = (value) => {  return value && value.length}/** * Pre-save hook */UserSchema  .pre('save', function (next) {    // Handle new/update passwords    if (!this.isModified('password')) {      return next()    }    if (!validatePresenceOf(this.password)) {      return next(new Error('密码错误'))    }    // Make salt with a callback    this.makeSalt((saltErr, salt) => {      if (saltErr) {        return next(saltErr)      }      this.salt = salt      this.encryptPassword(this.password, (encryptErr, hashedPassword) => {        if (encryptErr) {          return next(encryptErr)        }        this.password = hashedPassword        return next()      })    })  })/** * Methods */UserSchema.methods = {  /**   * Authenticate - check if the passwords are the same   *   * @param {String} password   * @param {Function} callback   * @return {Boolean}   * @api public   */  authenticate(password, callback) {    if (!callback) {      return this.password === this.encryptPassword(password)    }    this.encryptPassword(password, (err, pwdGen) => {      if (err) {        return callback(err)      }      if (this.password === pwdGen) {        return callback(null, true)      } else {        return callback(null, false)      }    })  },  /**   * Make salt   *   * @param {Number} [byteSize] - Optional salt byte size, default to 16   * @param {Function} callback   * @return {String}   * @api public   */  makeSalt(byteSize, callback) {    var defaultByteSize = 16    if (typeof arguments[0] === 'function') {      callback = arguments[0]      byteSize = defaultByteSize;    } else if (typeof arguments[1] === 'function') {      callback = arguments[1]    } else {      throw new Error('却少回调方法')    }    if (!byteSize) {      byteSize = defaultByteSize    }    return crypto.randomBytes(byteSize, (err, salt) => {      if (err) {        return callback(err)      } else {        return callback(null, salt.toString('base64'))      }    })  },  /**   * Encrypt password   *   * @param {String} password   * @param {Function} callback   * @return {String}   * @api public   */  encryptPassword(password, callback) {    if (!password || !this.salt) {      if (!callback) {        return null      } else {        return callback('却少密码或者加密内容')      }    }    var defaultIterations = 10000    var defaultKeyLength = 64    var salt = new Buffer(this.salt, 'base64')    if (!callback) {      return crypto.pbkdf2Sync(password, salt, defaultIterations, defaultKeyLength)        .toString('base64')    }    return crypto.pbkdf2(password, salt, defaultIterations, defaultKeyLength, (err, key) => {      if (err) {        return callback(err)      } else {        return callback(null, key.toString('base64'))      }    })  }}module.exports = mongoose.model('User', UserSchema)
 |