入门 | egg.js 入门之egg-jwt

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 小小继续学习,这次学习的内容是egg-jwt 相关。

小小继续学习,这次学习的内容是egg-jwt 相关。

创建egg项目

这里创建一个egg新项目,这里使用的是ts模式。

npm init egg --type=ts
npm install 

安装相关的包

这里创建并安装完成以后,需要再次初始化俩包,分别为egg-cors与egg-jwt token 生成的验证包

npm install egg-cors egg-jwt --save 

配置相关插件

这里配置相关的插件

import { EggPlugin } from 'egg';

const plugin: EggPlugin = {
  jwt: {
    enable: true,
    package: "egg-jwt"
  },
  cors: {
    enable: true,
    package: 'egg-cors',
  }
};

export default plugin;

配置默认配置文件

config.jwt = {
  secret: "123456"//自定义 token 的加密条件字符串
};
config.security = {
  csrf: {
    enable: false,
    ignoreJSON: true
  },
  domainWhiteList: ['http://localhost:8080'],//允许访问接口的白名单
};
config.cors = {
  origin:'*',
  allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH'
};

这里配置完成了相关的默认配置

在根目录声明any类型

这里需要在跟目录声明一个any类型,用于前后端发送相关的字符串参数。

import 'egg';
declare module 'egg' {
    interface Application {
        jwt: any;
    }
}

配置相关路由

这里在app/router.ts 创建相关的路由

import { Application } from 'egg';

export default (app: Application) => {
  const { controller, router, jwt } = app;
  
  //正常路由
  router.post('/admin/login', controller.admin.login);
  
  /* 
  * 这里的第二个对象不再是控制器,而是 jwt 验证对象,第三个地方才是控制器
  * 只有在需要验证 token 的路由才需要第二个 是 jwt 否则第二个对象为控制器
  **/
  router.post('/admin',jwt, controller.admin.index); 
};

这里就配置完成了相关的路由。

编写路由对应的控制器

这里编写路由所对应的控制器
这个控制器在app/controller/home.ts 目录下

import { Controller } from 'egg';

export default class AdminController extends Controller {

  // 验证登录并且生成 token
  public async login() {
    const { ctx ,app} = this;
    
    //获取用户端传递过来的参数
    const data = ctx.request.body;
    
    // 进行验证 data 数据 登录是否成功
    // .........
    //成功过后进行一下操作
    
    //生成 token 的方式
    const token = app.jwt.sign({
    
     username: data.username, //需要存储的 token 数据
     //......
     
    }, app.config.jwt.secret);
    // 生成的token = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE1NjAzNDY5MDN9.B95GqH-fdRpyZIE5g_T0l8RgzNyWOyXepkLiynWqrJg
    
    // 返回 token 到前端
    ctx.body = token;
  };

  //访问admin数据时进行验证token,并且解析 token 的数据
  public async index() {
  
    const { ctx ,app} = this;
    
    console.log(ctx.state.user);
    /* 
    * 打印内容为:{ username : 'admin', iat: 1560346903 }
    * iat 为过期时间,可以单独写中间件验证,这里不做细究
    * 除了 iat 之后,其余的为当时存储的数据
    **/
    
    ctx.body = {code:0,msg:'验证成功'};
  }
}

前端请求相匹配

这里只需要在前端的authorization字段里,添加相关的配置信息即可。

axios({
 method: 'post',
  url: 'http://127.0.0.1:7001/admin',
  data: {
    username: 'admin',
    lastName: '123456'
  },
  headers:{
      // 切记 token 不要直接发送,要在前面加上 Bearer 字符串和一个空格
    'Authorization':`Bearer ${token}`
  }
}).then(res=>{
  console.log(res.data)
})

这里就完成了egg.js 结合jwt完成相关的验证

小tips

这里插曲一个小tips,这里使用的是jsonwebtoken。这里使用jsonwebtoken实现token相关认证机制。

安装

这里安装相关的依赖

npm install jsonwebtoken

编写中间件

在middleware文件下新建一个jwt.ts 文件

'use strict'
const fs = require('fs')
const path = require('path')
const jwt = require('jsonwebtoken') //引入jsonwebtoken

module.exports = (options, app) => {
  return async function userInterceptor(ctx, next) {
    let authToken = ctx.header.authorization // 获取header里的authorization
    if (authToken) {
      authToken = authToken.substring(7)
      const res = verifyToken(authToken) // 解密获取的Token
      if (res.corpid && res.userid) {
        // 如果需要限制单端登陆或者使用过程中废止某个token,或者更改token的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效
        // 此处使用redis进行保存
        const redis_token = await app.redis.get('loginToken').get(res.corpid + res.userid) // 获取保存的token
        if (authToken === redis_token) {
          ctx.locals.corpid = res.corpid
          ctx.locals.userid = res.userid
          await next()
        } else {
          ctx.body = { code: 50012, msg: '您的账号已在其他地方登录' }
        }
      } else {
        ctx.body = { code: 50012, msg: '登录状态已过期' }
      }
    } else {
      ctx.body = { code: 50008, msg: '请登陆后再进行操作' }
    }
  }
}

// 解密,验证
function verifyToken(token) {
  const cert = fs.readFileSync(path.join(__dirname, '../public/rsa_public_key.pem')) // 公钥,看后面生成方法
  let res = ''
  try {
    const result = jwt.verify(token, cert, { algorithms: [ 'RS256' ] }) || {}
    const { exp } = result,
      current = Math.floor(Date.now() / 1000)
    if (current <= exp) res = result.data || {}
  } catch (e) {
    console.log(e)
  }
  return res
}

使用中间件

这里在config.default.js中加入如下的配置,实现中间件的开启和配置

// 方法一:在应用中使用中间件
config.middleware = [ 'jwt' ]

config.jwt = {
    enable: true,
    ignore: [ '/api/v1/test/', '/public/' ], // 哪些请求不需要认证
}

// 方法二:router中使用中间件
module.exports = app => {
  const jwt = app.middleware.jwt();
  app.router.get('/api/v1/test/', jwt, app.controller.test.test);
};

token生成

这里卸载文件里,用于调用,生成相关的token

loginToken(data, expires = 7200) {
  const exp = Math.floor(Date.now() / 1000) + expires
  const cert = fs.readFileSync(path.join(__dirname, '../public/rsa_private_key.pem')) // 私钥,看后面生成方法
  const token = jwt.sign({ data, exp }, cert, { algorithm: 'RS256' })
  return token
}

调用相关的生成方法

const token = ctx.helper.loginToken({ corpid: usersData.corpid, userid: usersData.userid }, 7200) // token生成
await app.redis.get('loginToken').set(usersData.corpid + usersData.userid, token, 'ex', 7200) // 保存到redis
ctx.body = { data: { token, expires: this.config.login_token_time }, code: 1, msg: '登录成功' } // 返回前端

前端使用

这里前端使用headers,在后面加上相关的空格。

例:axios中
// request拦截器
service.interceptors.request.use(config => {
  if (store.getters.token) {
    config.headers['Authorization'] = `Bearer ${getToken()}`
  }
  return config
}, error => {
  console.log(error)
  Promise.reject(error)
})

这里就完成了相关jwt的生成与使用。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
1月前
|
JavaScript 前端开发 C语言
javascript基础入门
javascript基础入门
23 1
|
3月前
|
JSON JavaScript 前端开发
Danfo.js专题 - Danfo.js与Dnotebook简介与入门
Danfo.js专题 - Danfo.js与Dnotebook简介与入门
46 0
|
3月前
|
JSON JavaScript 前端开发
Webpack【Webpack图片处理、Webpack中proxy代理 、自动清理dist、Webpack优化、JavaScript中的代码检查】(三)-全面详解(学习总结---从入门到深化)(下)
Webpack【Webpack图片处理、Webpack中proxy代理 、自动清理dist、Webpack优化、JavaScript中的代码检查】(三)-全面详解(学习总结---从入门到深化)
49 2
|
2月前
|
JavaScript
Node.js【GET/POST请求、http模块、路由、创建客户端、作为中间层、文件系统模块】(二)-全面详解(学习总结---从入门到深化)
Node.js【GET/POST请求、http模块、路由、创建客户端、作为中间层、文件系统模块】(二)-全面详解(学习总结---从入门到深化)
27 0
|
3月前
|
JavaScript
Node.js【GET/POST请求、http模块、路由、创建客户端、作为中间层、文件系统模块】(二)-全面详解(学习总结---从入门到深化)(上)
Node.js【GET/POST请求、http模块、路由、创建客户端、作为中间层、文件系统模块】(二)-全面详解(学习总结---从入门到深化)
29 0
|
2月前
|
消息中间件 Web App开发 JavaScript
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)
70 0
|
3月前
|
JavaScript 前端开发 API
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)(下)
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)
34 0
|
3月前
|
消息中间件 Web App开发 JavaScript
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)(上)
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)
42 0
|
3月前
|
JavaScript
Node.js【GET/POST请求、http模块、路由、创建客户端、作为中间层、文件系统模块】(二)-全面详解(学习总结---从入门到深化)(下)
Node.js【GET/POST请求、http模块、路由、创建客户端、作为中间层、文件系统模块】(二)-全面详解(学习总结---从入门到深化)
25 0
|
2月前
|
前端开发 JavaScript
从零开始学习前端开发:HTML、CSS、JavaScript入门指南
【2月更文挑战第1天】本文将带领读者从零开始学习前端开发,介绍HTML、CSS和JavaScript的基础知识与应用,帮助读者快速入门前端开发领域。
62 1