【koa2】用户注册、登录校验与加盐加密

加密与解密

 先介绍一下关于服务端用户名跟密码的存储状态,我们知道当前端在注册一个新用户时,会在表单内填入用户名和密码,并通过post请求提交到服务器,服务器再把用户名和密码从ctx.request.body中拿出来,存入到数据库的一张表里。这张表通常会被命名为users。

  关键在于,服务器如何存入用户名和密码到数据库。直接存?不可能的,这样太不安全了,永远不要在一张表中出现全部用户名和密码一览无余的危险情况。

  所以比较好的处理方法是这样的,服务器先对用户的密码进行加盐加密,再存到数据库。

  那密码验证呢?则是接收前端输入的明文密码,与数据库中相应的加密密码进行比对,如果正确,则表示登录成功。注意:如果有人拿到这个加密的密码,也是没用的。因为比对正误的方法已经在服务器写死,只能是比对明文密码与加密密码是否吻合。如果接收到两个一模一样的加密密码,验证也不会通过。

  至于如何比对明文密码与加密密码,不用担心,加密解密的方法都是一起配对生产的。bcryptjs就是这样一款不错的加解密工具。(因为在windows上安装bcrypt会报错,据说其他系统没问题,所以改为安装bcryptjs,其api和使用方法与bcrypt完全一样)

  我在一个js模块中定义了两个方法,一个加密,一个解密。在加密算法中,首先我们需要生成盐,所谓盐,就是先在明文密码中混入一些无规则的字符。传入的数字越大,代表混入的盐越复杂。最后通过hashSync方法生成加密密码并返回。而解密方法就更加简单,直接调用封装的compareSync方法进行明文密码与加密密码比对。

  

用户注册

  在服务端路由模块,暴露一个register接口,用于接收前端注册信息,对密码进行加盐加密,并存入数据库的操作。

const router = require("koa-router")();
const UserModel = require("../schema/user");
const Crypt = require("./crypt");
const jwt = require("jsonwebtoken");

// 新增一名用户
router.post("/register", async ctx => {
  const UserEntity = new UserModel(ctx.request.body);
  UserEntity.password = Crypt.encrypt(UserEntity.password);
  await UserEntity.save()
    .then(() => {
      ctx.body = {
        code: 200,
        msg: "register successfuly"
      };
    })
    .catch(() => {
      ctx.body = {
        code: 500,
        msg: "register failed"
      };
    });
});

(看一下我这段代码,有几个需要说明的地方:第一,我是通过userModel这一个模型的save方法将这条数据存入mongoDB数据库中,至于model、schema的概念问题,先不在这里赘述;第二:存储失败的原因可能是网络问题,服务端程序出错,但最大的可能还是因为我在userSchema里定义了用户名的不可重复性,也就是所谓的“该用户名已存在”)。

  为了阐述方便,这里将userModel的定义代码贴出来:

  

 

 

登录校验

  让我们回到服务端路由模块,看下怎样去完成一个登录校验。

  

// 登录校验
router.post("/login", async ctx => {
  const data = ctx.request.body;
  await UserModel.findOne({ account: data.account })
    .then(res => {
      const checkPassword = Crypt.decrypt(data.password, res.password);
      if (checkPassword) {
        const token = jwt.sign({ account: res.account }, "zhangnan", {
          expiresIn: "2h"
        });
        ctx.body = { code: 200, msg: "successfuly login", token: token };
      } else {
        ctx.body = { code: 500, msg: "wrong password" };
      }
    })
    .catch(() => {
      ctx.body = { code: 501, msg: "user does not exist" };
    });
});

  首先,我们根据用户输入的用户名去数据库查找用户信息,如果查不到,说明用户名不存在,这是第一层逻辑。

  如果查到了,则调用刚刚定义好的解密方法进行明文密码与加密密码比对,如错误,则告诉前端密码错误;如正确,则调用jwt的sign方法签发一个token给前端。签发的内容是用户名;后面前端再发来请求并携带这个token时,如果验证到token有效,那解析出来的用户名就是服务器判断前端请求身份的标识,它告诉服务器“我是xxx,且我处于已登录状态”。这是第二层逻辑。

  

 

posted @ 2019-07-22 10:38  陌上兮月  阅读(1820)  评论(0编辑  收藏  举报