Koa & Mongoose & Vue实现前后端分离--07登录加密&服务端参数校验

米花儿团儿

上节回顾

  • Elementscssaxios的使用
  • 路由定义与跳转
  • 登录&注册客户端逻辑

工作内容

  • crypto-js加密
  • 服务端参数校验

准备工作

  • npm i -S crypto-js // 先切换到/client目录下
  • npm install -S koa-bouncer // 先切换到/server目录下

更新逻辑

前端加密

上几节保存的密码都是明文的,这里借助crypto-js加密密码。

// 更新文:client/src/views/login/index.vue
...
import md5 from 'crypto-js/md5'
...
const res = await http.post(
'/users?action=login',
{
  account,
  password: md5(password).toString()
}
)
...
const res = await http.post(
'/users?action=register',
{
  account,
  password: md5(password).toString()
}
)
...

在请求登录 & 注册接口传参时,进行加密。
测试结果
md5
动态测试结果
register.gif

后端校验

在前端表单提交中,有校验逻辑:
validation
可是,通过Postman/其它方式请求接口时,不会走这些校验,所以,后端校验是很必要的。

不借助库校验

不借助第三方包的话,就自定义一个中间件(这里举特例)

// 新建文件:server/validation/user.js
const validate = (ctx, next) => {
  const { account, password } = ctx.request.body;
  // account: [
  //   { required: true, message: '请输入帐号', trigger: 'blur' },
  //   { min: 5, message: '长度至少5个字符', trigger: 'blur' }
  // ],
  // password: [
  //   { required: true, message: '请输入密码', trigger: 'blur' },
  //   { min: 3, message: '长度至少3个字符', trigger: 'blur' }
  // ]
  if (!account || !password) {
    ctx.body = {
      code: '403',
      data: null,
      msg: '帐号/密码不能为空'
    }
    return;
  }
  if (account.trim().length < 5) {
    ctx.body = {
      code: '403',
      data: null,
      msg: '帐号长度至少5个字符'
    }
    return;
  }
  next()
}

module.exports = {
  validate
}
// 更新文件:server/router/users.js
...
const { validate } = require('../validation/user'); //新增
...
  {
    path: '/',
    method: 'POST',
    handle: async (ctx) => {
        ...
    },
    middlewares: [
      validate //新增
    ]
  },
...
//更新文件:server/utils/router.js
function register(routes) {
  routes.forEach((route, idx) => {
    const { path, method, middlewares = [], handle } = route; // 加入middlewares
    this[method.toLowerCase()](path, ...middlewares, async (ctx, next) => {
      await handle(ctx);
    })
  })
}
module.exports = {
  register,
}

使用koa-bouncer校验

和‘不借助库校验’二选一,使用该方法时,注意还原‘不借助库校验’的代码。

// 更新文件:server/app.js
...
const bouncer = require('koa-bouncer'); //新增
const routes = require('./router');

const app = new koa();
app.use(cors());
app.use(bouncer.middleware()); //新增
// 中间件的错误处理
app.use(function(ctx, next){//新增
    console.log(err)
    if (err.name === 'ValidationError') { //bouncer校验失败会抛出错误,根据错误类型作出相应处理
      ctx.body = {
        code: '403',
        data: null,
        msg: err.message
      }
    }
  });
});
... 

bouncer校验失败会抛出错误,根据错误类型作出相应处理

// 更新文件:server/router/users.js
...
const validate = async (ctx, next) => {
  ctx.validateBody('account')
    .required('帐号必填')
    .isString('帐号必须是字符串')
    .trim()
    .tap(x => x.length)
    .gte(4, '帐号长度至少为5个字符')
  ctx.validateBody('password')
    .required('密码必填')
    .isString('密码必须是字符串')
    .trim()
  await next(); // 这里必须是async/await形式,否则,如动态图,没有返回值。
}
...

  {
    path: '/',
    method: 'POST',
    handle: async (ctx) => {
      const { action } = ctx.query;
      switch (action) {
        case 'register':
          await register(ctx);
          break;
        case 'login':
          await login(ctx);
          break;
        default:
          await list(ctx);
      }
    },
    middlewares: [
      validate // 新增
    ]
  },
...
//更新文件:server/utils/router.js
function register(routes) {
  routes.forEach((route, idx) => {
    const { path, method, middlewares = [], handle } = route; // 加入middlewares
    this[method.toLowerCase()](path, ...middlewares, async (ctx, next) => {
      await handle(ctx);
    })
  })
}
module.exports = {
  register,
}

测试结果
bouncer
动态测试结果
koa-bouncer.gif

参考文档

crypto-js
koa-bouncer

阅读 1.2k

1.2k 声望
68 粉丝
0 条评论
1.2k 声望
68 粉丝
文章目录
宣传栏