在上一篇文章,咱们曾经应用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.encryptthis.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设置在AuthorizationBearer Token字段中,再试一次,胜利了!

如果你跟我走到了这一步,那阐明你曾经间隔一个合格的服务端开发者更近了一步,然而这里咱们如同并没有用到token外面携带的信息,下一篇咱们将会解析token携带的信息,晓得每次都是哪个用户在拜访咱们的服务,而且咱们将优化咱们的代码,让它看起来更简洁、正当。