中间件

egg是一个基于koa的框架,中间件是一个函数,在请求与响应之间执行。
上篇博客的登录验证中,获取数据需要校验token,而token校验是写在controller里的。如果代码多起来,很多操作都需要校验token
每个controller都写个校验token的语句就比较繁琐。所以用中间件来完成请求与响应间校验token的功能

创建中间件

middleware目录别写错,写错egg就不认为你写了中间件


点击3次获取数据,后台也会打印3次checktoken。也就是说前台发出请求后,后台要经过中间件才能跳转到控制器

jwt.js

const Controller = require("egg").Controller

class JwtController extends Controller {
    async index(){
        this.ctx.body = "hi,egg";
    }

    async doLogin(){//处理用户登录,验证成功就发个token
        let user = this.ctx.request.body.user;//前端传过来的user,包含username和password属性
        if(user.username === "admin" && user.password === "123456"){
            let user_jwt = {userjwt:user.username};//用user.username来签名生成token
            let token = this.app.jwt.sign(user_jwt,this.app.config.jwt.secret);
            //let token = this.app.jwt.sign({username},this.app.config.jwt.secret);
            //这是种简写法,展开来是这样的{username:username},属性username的值是username
            this.ctx.body = {
                code:20000,
                token:token
            }//验证成功就给个响应,code和token是自己定义的,像msg那样
        }else{//登录失败的响应
            this.ctx.body = {
                code:40000,
                msg:"用户名或密码错误"
            }
        }
    }

    async getMessage(){//前端向后台获取信息时校验token
        this.ctx.body = "hello jwt";//有中间件就不需要写token校验了
    }
}

module.exports = JwtController

checktoken.js

function checktoken(){
    return async function(ctx,next){//ctx上下文对象,next路由放行
        try{
            let token = ctx.request.header.token;//获取请求头里的token属性的值,不能加this
            //用户再次请求数据的时候都要带着生成的token给服务器校验
            let decode = ctx.app.jwt.verify(token,ctx.app.config.jwt.secret);//ctx.app可以指向应用实例app
            console.log(decode)
            if(decode.userjwt){
                /*如果jwt.js的doLogin中用user生成的token,
                那么decode:{ username: 'admin', password: '123456', iat: 1675928007 }
                有username和password两个属性,这种情况是decode.username
                如果用user_jwt生成的token,由于user_jwt是{userjwt:user.username}定义的
                所以它只有一个属性,userjwt,值为user对象的username
                decode:{ userjwt: 'admin', iat: 1675928083 }
                jwt.js采用user_jwt生成token,所以是decode.userjwt
                两种生成token的方式都可以,user容易理解,user_jwt更贴合实际
                */
                await next();//放行
            }
        }catch(e){
            ctx.body = {
                code:40000,
                msg:"用户校验失败"
            }
        }
    }
}

module.exports = checktoken;

router.js

'use strict';//严格模式

/**
 * @param {Egg.Application} app - egg application
 */
module.exports = app => { 
  const { router, controller } = app;
  router.get('/', controller.home.index);
  router.resources("students","/students",controller.students);
  router.get('/jwt', controller.jwt.index);
  router.post('/jwtlogin', controller.jwt.doLogin);//处理前端/login提交的表单
  router.get('/jwtmessage', app.middleware.checktoken(), controller.jwt.getMessage);
  //每次get请求访问/jwtmessage时都会执行中间件checktoken()方法来校验token
};

vue跟上篇博客一样

posted @ 2023-02-09 15:49  ben10044  阅读(7)  评论(0编辑  收藏  举报