在上一篇文章,咱们曾经应用Sequelize连贯上了数据库,并能进行简略的数据库操作,在此基础上,咱们试着来开发一个残缺的我的项目。这篇文章咱们从用户的注册、登录着手,试着开发用户模块的相干的代码。
用户注册
1. 注册逻辑
用户注册的逻辑很简略:
- 客户端:用户输出输出账号,明码等信息进行用户注册;
- 服务端:接管到客户端提交的注册信息后,进行字段的测验(是否必填、字段长度等),字段符合要求后,依据用户注册的账号查询数据库,依据返回后果判断该用户是否是新用户,如果是新用户,将用户信息写入到数据库,实现注册流程。
2. 用户明码解决
客户端用户提交数据后,服务端验证通过进行数据库写入,然而其中用户明码是敏感信息,为了服务平安思考,不能间接将明文明码写入到数据库,避免数据库被攻打,用户明码泄露。所以个别在存储用户明码时,会先对用户明码进行加盐加密解决,这样哪怕数据库存储的明码泄露,其他人也无奈通过解决后的明码进行登录。这里应用哈希算法对明码进行加密,因为哈希的个性是不可逆,具体的细节能够参考为什么说 MD5 是不可逆的?。阐明:哈希能够被暴力破解,加盐能够很大水平上减少破解难度。
废话不多说,咱们上面来写代码。
首先,咱们装置一下bcryptjs
,咱们应用它对明码进行加盐加密和比对:
npm install bcryptjs --save
而后咱们把这两个办法写到app/extend/helper.js
:
const bcrypt = require('bcryptjs');module.exports = { encrypt(password) { const salt = bcrypt.genSaltSync(5); //加盐 const hash = bcrypt.hashSync(password, salt); //哈希(同步调用) return hash; }, compare(password, hash) { return bcrypt.compareSync(password, hash); //比对 }};
这样咱们在我的项目里就能够通过this.ctx.helop.encrypt
和this.ctx.helop.compare
的形式去应用这些专用的办法了。
而后,在UserController
中增加一个register
办法:
async register() { const params = this.ctx.request.body; // 参数校验 if (!params.name || !params.password || !params.phone || !params.email) { this.ctx.body = { code: '500', msg: '参数不非法' }; } // 查问该用户是否曾经注册 const user = await this.ctx.model.User.findOne({ where: { name: params.name } }); if (user) { this.ctx.body = { code: '500', msg: '该用户已存在' }; } // 插入数据库 const result = await this.ctx.model.User.create({ ...params, password: this.ctx.helper.encrypt(params.password) }); if (result) { this.ctx.body = { code: '200', msg: '注册胜利' }; }}
最初,增加路由:
// app/router.jsrouter.post('/register', controller.user.register);
3.功能测试
测试一下,用postman创立一个post申请到localhost:7001/register
,传入注册用户信息:
{ "name":"xiaoming", "password":"test1234", "phone":"13412341234", "email":"test@gmai.com"}
服务端返回“注册胜利”的提醒语,这时候咱们去数据库就能看到这条数据了,而且明码是一坨看不懂的密文,这个时候咱们用同样的数据再次发动申请,服务端返回“该用户已注册”,阐明咱们的注册性能曾经实现了!
用户登录
用户登录的逻辑很简略,就是一个客户端传入的用户名明码与服务器存储的相比拟,匹配就登录胜利,不然就是用户名明码谬误。然而,咱们还须要额定思考一个问题,http申请是无状态的,那咱们怎么去记住用户的登录状态和登录信息呢,并且每次向服务端发动申请都带上这些信息呢?
罕用的用户认证形式有两种,一种是通过Cookie实现,一种是Token的实现形式。对于用户受权认证能够看看这篇文章:受权认证登录之 Cookie、Session、Token、JWT 详解,Eggjs官网也有一个章节讲了Cookie和Session相干的常识Cookie 与 Session,学习服务端,把握这些常识还是很必要的。
在这里,咱们抉择JWT作为咱们的解决方案。对于JWT,这里提供两篇文章作为参考,JSON Web Token 入门教程,Introduction to JSON Web Tokens。OK,原理看完当前咱们来写代码。
首先咱们装置egg-jwt
插件:
npm install egg-jwt --save
引入插件:
// app/config/plugin.jsjwt: { enable: true, package: "egg-jwt"}
配置jwt secret:
// app/config/config.default.jsconfig.jwt = { secret: '12312456};
OK,咱们上面编写代码的代码:
// app/controller/user.jsasync login() { const params = this.ctx.request.body; if (!params.name || !params.password) { this.ctx.body = { code: '500', msg: '参数不非法' } } const user = await this.ctx.model.User.findOne({ where: { name: params.name } }); if (!user) { this.ctx.body= { code: '500', msg: '用户名明码谬误' } } //校验明码 const checkPassword = this.ctx.helper.compare( params.password, user.password ); if (checkPassword) { // 依据用户名称创立token,过期工夫为2小时 const token = this.app.jwt.sign({ name: user.name }, this.app.config.jwt.secret, { expiresIn: '2h' }); this.ctx.body = { code: '200', data: token } } else { this.ctx.body = { code: '500', msg: '用户名明码谬误' } }}
配置路由:
// app/router.jsrouter.post('/login', controller.user.login);
代码结束,让咱们测试一下,创立一个post申请到localhost:7001/login
,输出用户名明码:
{ "name":"xiaoming", "password":"test1234"}
后果如下:
{ "code": "200", "data": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoieGlhb21pbmciLCJpYXQiOjE2MDg1NTkzMTYsImV4cCI6MTYwODU2NjUxNn0.SyXAhVvrwAql-4FzaZrlEs6dsEJ4wXbdjQsHv43CSOI"}
胜利了,这一大坨就是咱们创立的token。
嗯……咱们是拿到了token,然而怎么用呢?还记得咱们最开始写的两个接口吗?咱们当初给他配置jwt验证,而后试试不登录能不能拜访。
// app/router.jsrouter.post('/createUser', app.jwt, controller.user.createUser);router.get('/getUsers', app.jwt, controller.user.getUsers);
而后咱们从新测试一下这两个接口,服务端返回401 Unauthorized
,这阐明验证失效了。那咱们在申请的时候把方才登录接口获取到的token设置在Authorization
的Bearer Token
字段中,再试一次,胜利了!
如果你跟我走到了这一步,那阐明你曾经间隔一个合格的服务端开发者更近了一步,然而这里咱们如同并没有用到token
外面携带的信息,下一篇咱们将会解析token
携带的信息,晓得每次都是哪个用户在拜访咱们的服务,而且咱们将优化咱们的代码,让它看起来更简洁、正当。