user.model.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. const crypto = require('crypto')
  2. const mongoose = require('mongoose')
  3. mongoose.Promise = require('bluebird')
  4. var UserSchema = new mongoose.Schema({
  5. name: String,
  6. loginId: {
  7. type: String,
  8. lowercase: true,
  9. required: true
  10. },
  11. role: {
  12. type: String,
  13. default: 'user'
  14. },
  15. password: {
  16. type: String,
  17. required: true
  18. },
  19. provider: String,
  20. salt: String,
  21. token: String
  22. });
  23. /**
  24. * Validations
  25. */
  26. // Validate empty email
  27. UserSchema
  28. .path('loginId')
  29. .validate((loginId) => {
  30. return loginId.length;
  31. }, '登陆名不能空');
  32. // Validate empty password
  33. UserSchema
  34. .path('password')
  35. .validate((password) => {
  36. return password.length;
  37. }, '密码不能空');
  38. // Validate loginId is not taken
  39. UserSchema
  40. .path('loginId')
  41. .validate(function (value, respond) {
  42. return this.constructor.findOne({loginId: value}).exec()
  43. .then(user => {
  44. if (user) {
  45. if (this.id === user.id) {
  46. return respond(true);
  47. }
  48. return respond(false);
  49. }
  50. return respond(true);
  51. })
  52. .catch((err) => {
  53. throw err;
  54. });
  55. }, '该用户已存在');
  56. var validatePresenceOf = (value) => {
  57. return value && value.length;
  58. };
  59. /**
  60. * Pre-save hook
  61. */
  62. UserSchema
  63. .pre('save', function (next) {
  64. // Handle new/update passwords
  65. if (!this.isModified('password')) {
  66. return next();
  67. }
  68. if (!validatePresenceOf(this.password)) {
  69. return next(new Error('密码错误'));
  70. }
  71. // Make salt with a callback
  72. this.makeSalt((saltErr, salt) => {
  73. if (saltErr) {
  74. return next(saltErr);
  75. }
  76. this.salt = salt;
  77. this.encryptPassword(this.password, (encryptErr, hashedPassword) => {
  78. if (encryptErr) {
  79. return next(encryptErr);
  80. }
  81. this.password = hashedPassword;
  82. return next();
  83. });
  84. });
  85. });
  86. /**
  87. * Methods
  88. */
  89. UserSchema.methods = {
  90. /**
  91. * Authenticate - check if the passwords are the same
  92. *
  93. * @param {String} password
  94. * @param {Function} callback
  95. * @return {Boolean}
  96. * @api public
  97. */
  98. authenticate(password, callback) {
  99. if (!callback) {
  100. return this.password === this.encryptPassword(password);
  101. }
  102. this.encryptPassword(password, (err, pwdGen) => {
  103. if (err) {
  104. return callback(err);
  105. }
  106. if (this.password === pwdGen) {
  107. return callback(null, true);
  108. } else {
  109. return callback(null, false);
  110. }
  111. });
  112. },
  113. /**
  114. * Make salt
  115. *
  116. * @param {Number} [byteSize] - Optional salt byte size, default to 16
  117. * @param {Function} callback
  118. * @return {String}
  119. * @api public
  120. */
  121. makeSalt(byteSize, callback) {
  122. var defaultByteSize = 16;
  123. if (typeof arguments[0] === 'function') {
  124. callback = arguments[0];
  125. byteSize = defaultByteSize;
  126. } else if (typeof arguments[1] === 'function') {
  127. callback = arguments[1];
  128. } else {
  129. throw new Error('却少回调方法');
  130. }
  131. if (!byteSize) {
  132. byteSize = defaultByteSize;
  133. }
  134. return crypto.randomBytes(byteSize, (err, salt) => {
  135. if (err) {
  136. return callback(err);
  137. } else {
  138. return callback(null, salt.toString('base64'));
  139. }
  140. });
  141. },
  142. /**
  143. * Encrypt password
  144. *
  145. * @param {String} password
  146. * @param {Function} callback
  147. * @return {String}
  148. * @api public
  149. */
  150. encryptPassword(password, callback) {
  151. if (!password || !this.salt) {
  152. if (!callback) {
  153. return null;
  154. } else {
  155. return callback('却少密码或者加密内容');
  156. }
  157. }
  158. var defaultIterations = 10000;
  159. var defaultKeyLength = 64;
  160. var salt = new Buffer(this.salt, 'base64');
  161. if (!callback) {
  162. return crypto.pbkdf2Sync(password, salt, defaultIterations, defaultKeyLength)
  163. .toString('base64');
  164. }
  165. return crypto.pbkdf2(password, salt, defaultIterations, defaultKeyLength, (err, key) => {
  166. if (err) {
  167. return callback(err);
  168. } else {
  169. return callback(null, key.toString('base64'));
  170. }
  171. });
  172. }
  173. };
  174. module.exports = mongoose.model('User', UserSchema);