回调
- hook.js
- 了解pre和post的差别
我们了解了crud是数据库的基本操作,可是你有想过么?当创建之前需要完成一些操作怎么弄呢?创建完成之后如果需要完成日志类操作呢?
当然我们可以
a()
b()
c()
其实如果是明确的生命周期,我们其实可以这样
pre_b()
b()
post_b()
如果这个生命周期类似于模板模式,实现了就起作用,没有实现就走默认行为,是不会非常好呢?在mongoose里其实也提供了类似机制,成为hook。简单点说就是给数据库操作方法增加pre和post回调,当数据库完成某些操作的时候,它会自动触发前置或后置行为的。
最典型的例子要数用户创建时密码的操作,出于安全的考虑,数据库里是不能明文存储的,md5是一种方式,但还是有一定风险的,所以比较好的办法是采用加盐hash的方法,可以有效的防范彩虹表等破译。
注册
在用户注册保存的时候,需要先把password通过salt生成hash密码,并最终赋值给password。
UserSchema.pre('save', function (next) {
var that = this;
bcrypt.genSalt(this._salt_bounds, function(err, salt) {
if (err) {
console.log(err);
return next();
}
bcrypt.hash(that.password, salt, function(error, hash) {
if (error) {
console.log(error);
}
// console.log(this.password + ' \n ' + hash);
//生成密文
that.password = hash;
return next();
});
});
})
测试
var user = new User({
name :'ss',
password: 'sdfsfsdfdsf'
});
user.save();
登录
UserSchema.statics.login = function(username, password, cb) {
this.findOne({
username: username
}, function (err, user) {
if (err || !user) {
if (err)
console.log(err);
return cb(err, {
code: -1,
msg : username + ' is not exist!'
});
}
bcrypt.compare(password, user.password, function(error, res) {
if (error) {
console.log(error);
return cb(err, {
code: -2,
msg : 'password is incorrect, please check it again!'
});
}
return cb(null, user);
});
});
};
说明
- 当用户名不存在的时候,返回{code: -1}
- 当密码不正确的时候,返回{code: -2}
- 如果校验正确,会返回user具体信息
测试
User.login('i5ting for is_login_valid', '0123456789', function (err, result) {
if (!err) {
t.pass()
t.end()
}
})
测试代码
db/hook/test.js
import test from 'ava';
// 1、引入`mongoose connect`
require('../connect');
// 2、引入`User` Model
const User = require('../user/hook/user');
// 3、定义`user` Entity
const user = new User({
username: 'i5ting',
password: '0123456789'
});
test.cb('#register()', t => {
user.save((err, u) => {
t.true(u.password.length > 50)
t.end()
})
});
test.cb('#User.login(username, password) sucess', t => {
let _user = new User({
username: 'i5ting for is_login_valid',
password: '0123456789'
});
_user.save((err, u) => {
User.login('i5ting for is_login_valid', '0123456789', function (err, result) {
if (!err) {
t.pass()
t.end()
}
})
})
});
test.cb('#User.login(username, password) fail with username is not exist', t => {
let _user = new User({
username: 'i5ting for is_login_valid',
password: '0123456789'
});
_user.save((err, u) => {
User.login('i5ting for is_login_valid not exist', '0123456789', function (err, result) {
if (err) {
console.log(err)
t.pass()
t.end()
}
if (result.code === -1) {
t.pass()
t.end()
}
})
})
});
test.cb('#User.login(username, password) fail with password is incorrect', t => {
let _user = new User({
username: 'i5ting for is_login_valid fail with password is incorrect',
password: '0123456789'
});
_user.save((err, u) => {
User.login('i5ting for is_login_valid fail with password is incorrect', '0123456', function (err, result) {
if (err) {
console.log(err)
t.fail()
t.end()
}
if (result) {
t.is(result.username, _user.username)
t.end()
}
})
})
});
执行测试
$ npm run hook
> koa-db@1.0.0 hook /Users/sang/workspace/17koa/book-source/db
> ava -v hook/test.js
数据库连接成功
✔ #User.login(username, password) fail with username is not exist (214ms)
✔ #register() (248ms)
✔ #User.login(username, password) fail with password is incorrect (350ms)
✔ #User.login(username, password) sucess (372ms)
4 tests passed