回调

  • hook.js
  • 了解pre和post的差别

我们了解了crud是数据库的基本操作,可是你有想过么?当创建之前需要完成一些操作怎么弄呢?创建完成之后如果需要完成日志类操作呢?

当然我们可以

  1. a()
  2. b()
  3. c()

其实如果是明确的生命周期,我们其实可以这样

  1. pre_b()
  2. b()
  3. post_b()

如果这个生命周期类似于模板模式,实现了就起作用,没有实现就走默认行为,是不会非常好呢?在mongoose里其实也提供了类似机制,成为hook。简单点说就是给数据库操作方法增加pre和post回调,当数据库完成某些操作的时候,它会自动触发前置或后置行为的。

最典型的例子要数用户创建时密码的操作,出于安全的考虑,数据库里是不能明文存储的,md5是一种方式,但还是有一定风险的,所以比较好的办法是采用加盐hash的方法,可以有效的防范彩虹表等破译。

注册

在用户注册保存的时候,需要先把password通过salt生成hash密码,并最终赋值给password。

  1. UserSchema.pre('save', function (next) {
  2. var that = this;
  3. bcrypt.genSalt(this._salt_bounds, function(err, salt) {
  4. if (err) {
  5. console.log(err);
  6. return next();
  7. }
  8. bcrypt.hash(that.password, salt, function(error, hash) {
  9. if (error) {
  10. console.log(error);
  11. }
  12. // console.log(this.password + ' \n ' + hash);
  13. //生成密文
  14. that.password = hash;
  15. return next();
  16. });
  17. });
  18. })

测试

  1. var user = new User({
  2. name :'ss',
  3. password: 'sdfsfsdfdsf'
  4. });
  5. user.save();

登录

  1. UserSchema.statics.login = function(username, password, cb) {
  2. this.findOne({
  3. username: username
  4. }, function (err, user) {
  5. if (err || !user) {
  6. if (err)
  7. console.log(err);
  8. return cb(err, {
  9. code: -1,
  10. msg : username + ' is not exist!'
  11. });
  12. }
  13. bcrypt.compare(password, user.password, function(error, res) {
  14. if (error) {
  15. console.log(error);
  16. return cb(err, {
  17. code: -2,
  18. msg : 'password is incorrect, please check it again!'
  19. });
  20. }
  21. return cb(null, user);
  22. });
  23. });
  24. };

说明

  • 当用户名不存在的时候,返回{code: -1}
  • 当密码不正确的时候,返回{code: -2}
  • 如果校验正确,会返回user具体信息

测试

  1. User.login('i5ting for is_login_valid', '0123456789', function (err, result) {
  2. if (!err) {
  3. t.pass()
  4. t.end()
  5. }
  6. })

测试代码

db/hook/test.js

  1. import test from 'ava';
  2. // 1、引入`mongoose connect`
  3. require('../connect');
  4. // 2、引入`User` Model
  5. const User = require('../user/hook/user');
  6. // 3、定义`user` Entity
  7. const user = new User({
  8. username: 'i5ting',
  9. password: '0123456789'
  10. });
  11. test.cb('#register()', t => {
  12. user.save((err, u) => {
  13. t.true(u.password.length > 50)
  14. t.end()
  15. })
  16. });
  17. test.cb('#User.login(username, password) sucess', t => {
  18. let _user = new User({
  19. username: 'i5ting for is_login_valid',
  20. password: '0123456789'
  21. });
  22. _user.save((err, u) => {
  23. User.login('i5ting for is_login_valid', '0123456789', function (err, result) {
  24. if (!err) {
  25. t.pass()
  26. t.end()
  27. }
  28. })
  29. })
  30. });
  31. test.cb('#User.login(username, password) fail with username is not exist', t => {
  32. let _user = new User({
  33. username: 'i5ting for is_login_valid',
  34. password: '0123456789'
  35. });
  36. _user.save((err, u) => {
  37. User.login('i5ting for is_login_valid not exist', '0123456789', function (err, result) {
  38. if (err) {
  39. console.log(err)
  40. t.pass()
  41. t.end()
  42. }
  43. if (result.code === -1) {
  44. t.pass()
  45. t.end()
  46. }
  47. })
  48. })
  49. });
  50. test.cb('#User.login(username, password) fail with password is incorrect', t => {
  51. let _user = new User({
  52. username: 'i5ting for is_login_valid fail with password is incorrect',
  53. password: '0123456789'
  54. });
  55. _user.save((err, u) => {
  56. User.login('i5ting for is_login_valid fail with password is incorrect', '0123456', function (err, result) {
  57. if (err) {
  58. console.log(err)
  59. t.fail()
  60. t.end()
  61. }
  62. if (result) {
  63. t.is(result.username, _user.username)
  64. t.end()
  65. }
  66. })
  67. })
  68. });

执行测试

  1. $ npm run hook
  2. > koa-db@1.0.0 hook /Users/sang/workspace/17koa/book-source/db
  3. > ava -v hook/test.js
  4. 数据库连接成功
  5. #User.login(username, password) fail with username is not exist (214ms)
  6. #register() (248ms)
  7. #User.login(username, password) fail with password is incorrect (350ms)
  8. #User.login(username, password) sucess (372ms)
  9. 4 tests passed