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

创立egg我的项目

这里创立一个egg新我的项目,这里应用的是ts模式。

npm init egg --type=tsnpm 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') //引入jsonwebtokenmodule.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) // 保留到redisctx.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的生成与应用。