使用egg-jwt进行路由鉴权以及登陆、注册接口的实现

前面我们已经链接上了数据库, 并且实现了基本的读写操作, 接下来我们来实现需要的几个接口

注册api

根据上面的流程, 我们来实现基本的注册能力

Controller

首先我们来新建一个控制器user, 用来处理用户相关的操作

在控制器内我们需要做几件事

  1. 获取到路由提交的用户名和密码
    1. 注册我们一般适用post提交, 所以此处我们使用query抓取参数
  1. 用获取的用户名和密码调用数据库查询
    1. 数据库相关的操作我们放在service下,我们此处可以先进行调用
  1. 返回信息
    1. 先将查询后的result直接返回
ini 复制代码
const { Controller } = require('egg');

class UserController extends Controller {
  async register() {
    const { ctx } = this;
    const { username, password } = ctx.query;
    const body = {
      code: 200,
      msg: '注册成功',
    };
    const result = await ctx.service.user.getUserByName(username);
    if (!result) {
      const res = await ctx.service.user.register({ username, password });
      if (res.affectedRows === 1) {
        body.code = 200;
        body.msg = '注册成功';
      } else {
        body.code = 500;
        body.msg = '注册失败';
      }
    } else {
      // 用户名已注册
      body.code = 500;
      body.msg = '用户名已注册';
    }
    ctx.body = body;
  }
}

module.exports = UserController;

代码里面,我们先调用getUserByName查询用户名是否呢已经注册, 根据结果我们才进行数据的添加注册

Service

根据上面控制器以及注册流程, 我们在seivice里面需要提供两个方法,分别处理

  1. 根据username字段查询用户名是否已经注册
  2. 注册功能, 也就是数据插入

创建app/service/user.js进行数据库相关的操作

javascript 复制代码
const { Service } = require('egg');

class UserService extends Service {
  // 根据username字段查询用户信息
  async getUserByName(username) {
    const { app } = this;
    const result = await app.mysql.get('user', { username });
    return result;
  }
  // 注册
  async register(params) {
    const { app } = this;
    const { username, password } = params;
    const ctime = new Date();
    const result = await app.mysql.insert('user', { username, password, ctime });
    return result;
  }
}

module.exports = UserService;

路由

最后我们来创建一个注册的路由

arduino 复制代码
module.exports = app => {
  const { router, controller } = app;
  // 注册
  router.post('/register', controller.user.register);
};

验证

完成上面所有的操作, 我们打开postman 进行一下验证, 请求两次, 分别验证注册一级重复注册

注册:

重复注册:

登陆

egg-jwt

jwt是什么此处就不多说了,百度上概念已经很详细了,我们使用的 egg-jwt 来实现路由鉴权部分

安装egga-jwt

安装依赖

sql 复制代码
npm add egg-jwt --save

注册插件

java 复制代码
module.exports = {
  ...
    jwt: {
  enable: true,
    package: 'egg-jwt',
    },
    ...

}

配置

arduino 复制代码
config.jwt = {
  secret: '123456', // 自定义的密钥字段
};

登陆api

首先我们在app/controller/user.js 中定一个login controller , 来实现登陆相关的逻辑

ini 复制代码
class UserController extends Controller {
  async login() {
    const { ctx, app } = this;
    const { username, password } = ctx.query;
    const body = {
      code: 200,
      msg: '登陆成功',
      data: {},
    };
    const userinfo = await ctx.service.user.getUserByName(username);
    if (userinfo && userinfo.password === password) {
      // 200
      body.code = 200;
      body.msg = '登陆成功';
    } else if (userinfo && userinfo.password !== password) {
      // password error
      body.code = 401;
      body.msg = '密码错误';
    } else {
      // 用户不存在
      body.code = 401;
      body.msg = '用户不存在';
    }
    ctx.body = body;
  }
}

通过ctx.query抓取到用户提交的信息 username `` password , 然后根据 username 去数据库 user表中查询相关用户信息, 进行对比。

以下我们定义 getUserByName 方法, 用来根据 username 去数据库 user表中查询相关用户信息

scala 复制代码
class UserService extends Service {

  async getUserByName(username) {
    const { app } = this;
    const result = await app.mysql.get('user', { username });
    return result;
  }
}

此处我们已经实现了基本的login 接口, 但登陆成功后, 我们需要返回token, 提供给前台, 用来进行后续接口请求的鉴权。

在上面的login 方法中继续补充token 返回

css 复制代码
body.data.token = app.jwt.sign({
  ...userinfo,
  time: Date.now(),
}, app.config.jwt.secret);

我们用当前时间生成token, 方便我们后面对比。此处需要说明我们在config中声明的变量, 在运行时都会挂载到app中的config字段上。

鉴权中间件

接下来我们需要思考一个问题, token生成后如何实现接口鉴权?

思路其实都是一样的, 就是在请求的接口中抓取token字段, 进行解析, 然后对比是否有效, 但具体如何实现才能更高效、简单呢?

前面我们在实现api的时候在每一个 Controller也就是接口的实现内都可以访问到ctx, 此时我们进行token 的判断, 也可以实现接口的鉴权, 但问题是, 这样写在每一个接口的实现内, 效率太低, 同时不方便维护。

此时, 我们就需要用到middleware 中间件, 在egg中我们需要开发中间件的时候只需要在 app/middleware/下直接新建就可以自动挂载到app上

接下来我们实现路有鉴权的中间件

ini 复制代码
module.exports = () => {
  return async function jwterror(ctx, next) {
    const { app, header: { token } } = ctx;
    if (!token) {
      ctx.body = {
        msg: '缺少token',
        code: 401,
      };
      return;
    }
    try {
      const userinfo = app.jwt.verify(token, app.config.jwt.secret);
      console.log(userinfo);
      await next();
    } catch (error) {
      ctx.body = {
        msg: 'token已过期,请重新登录',
        code: 401,
      };
    }

  };
};

抓取到 header 中的token 字段后, 我们调用 jwt.verify() 来进行解析。获取到 userinfo 之后我们只需要对比一下是否生效就可以了, 此处对比根据需求自行实现。

中间件实现后, 具体如何调用, 常见的会有两种方式

  1. 全局

也就是挂载到全局, 会在所有的路由上生效。

具体就是 在config/config.default.js中定义

ini 复制代码
config.middleware = [ 'jwterror' ];
  1. 按需

但有时候我们又不是所有的路由都需要鉴权, 就比如登陆、注册。 前面说了middleware会挂载到app上, 所以我们在定义路有的时候在需要的路由上进行调用就可以了

ini 复制代码
module.exports = app => {
  const { router, controller, middleware } = app;
  const jwterror = middleware.jwterror();

  
  router.get('/list', jwterror, controller.account.list);
};

需要注意的是,middleware挂载的是定义的jwterror方法, 执行后return 出来的是内部的jwterror 函数。

相关推荐
雾岛听风来3 分钟前
前端开发 如何高效落地 Design Token
前端
来之梦24 分钟前
uniapp中 uni.previewImage用法
前端·javascript·uni-app
野猪佩奇00731 分钟前
uni-app使用ucharts地图,自定义Tooltip鼠标悬浮显示内容并且根据@getIndex点击事件获取点击的地区下标和地区名
前端·javascript·vue.js·uni-app·echarts·ucharts
2401_857026231 小时前
拖动未来:WebKit 完美融合拖放API的交互艺术
前端·交互·webkit
星辰中的维纳斯2 小时前
vue新手入门教程(项目创建+组件导入+VueRouter)
前端·javascript·vue.js
嫣嫣细语2 小时前
css实现鼠标禁用(鼠标滑过显示红色禁止符号)
前端·css
Days20502 小时前
web前端主要包括哪些技术
前端
XF鸭2 小时前
HTML-CSS 入门介绍
服务器·前端·javascript
forwardMyLife3 小时前
element-plus 的form表单组件之el-radio(单选按钮组件)
前端·javascript·vue.js
fs哆哆3 小时前
ExcelVBA运用Excel的【条件格式】(二)
linux·运维·服务器·前端·excel