• home > webfront > server > koa >

    koa网站安全之JWT鉴权详解:koa-router与koa-jwt分模块鉴权实

    Author:zhoulujun Date:

    koa-jwt全局鉴权配置很简单。但是如何实现分模块鉴权,比如后台管理系统需要全局鉴权,前端web访问部分只需部分接口需要鉴权。不同模块鉴权方式不一样,如何配置。首先熟悉koa-router

    首先看koa-router



    koa-router use

    熟悉Koa的同学都知道use是用来注册中间件的方法,相比较Koa中的全局中间件,koa-router的中间件则是路由级别的。

    koa-router中间件注册方法主要完成两项功能

    • 将路由嵌套结构扁平化,其中涉及到路由路径的更新和param前置处理函数的插入;

    • 路由级别中间件通过注册一个没有method的Layer实例进行管理。

    具体参看:玩转Koa -- koa-router原理解析 https://zhuanlan.zhihu.com/p/54960421

    https://github.com/koajs/router/blob/master/API.md#module_koa-router--Router+use

    koa-router添加中间件:

    router.use([path], middleware) ⇒ Router

    // session middleware will run before authorizerouter
      .use(session())
      .use(authorize());
      // use middleware only with given path
      router.use('/users', userAuth());
      // or with an array of paths
      router.use(['/users', '/admin'], userAuth());
      app.use(router.routes());

    更多可以参看:koa2学习笔记:koa-router使用方法及多路由代码组织 www.shanhuxueyuan.com/news/detail/128.html


    koa koa-router路由层级 路由模块化

    主应用中加载子路由模块:

    let api = require('./api');
    let admin = require('./admin');
    let login = require('./login');
    const koaJwt = require('koa-jwt');
    const Const = require('../const');
    const cors = require('koa2-cors');
    module.exports = (app) => {
        app.use(login.routes());
        //这是处理前端跨域的配置
        //这是处理前端跨域的配置
        app.use(cors(
            {
                /* origin: function (ctx) {
                   // if (ctx.url === '/login') {
                   //   return "*"; // 允许来自所有域名请求
                   // }
                   return '*';
                 },*/
                exposeHeaders: ['WWW-Authenticate', 'Server-Authorization'],
                maxAge: 5,
                credentials: true,
                allowMethods: ['GET', 'POST', 'DELETE'],
                allowHeaders: ['Content-Type', 'Authorization', 'Accept'],
            }
        )).use(api.routes());
        app.use(koaJwt({
            secret: Const.TokenGlobal
        }).unless({ // 配置白名单
            method: 'get',
            path: [
                /\/api\/img/
            ]
        })).use(admin.routes());
    }

    子模块示例:

    const Router = require('koa-router')
    const newsRouter = new Router({
      prefix: '/user' //前缀
    })
    const apiController = require('../controller/api')
    newsRouter.post('/login', apiController.login)
    module.exports  = newsRouter

    不同模块,分配不同的前缀

    具体参看:koa2 router koa-router路由配置 bbs.itying.com/topic/5bcc1afb0e32ae0ac45a76e8

    koa-jwt  实现模块化鉴权

    百度谷歌能搜到的基本都是如此:koa-jwt 实现自定义排除动态路由的鉴权 # https://jwchan.cn/_posts/backend/node/koa_jwt_unless.html#场景描述

    主要是使用koa-jwt的 unless , koa-jwt 的 unless 方法调用了 koa-unless 这个包,于是去阅读了 koa-unless 之后,发现可配置以下参数:

    • - method 它可以是一个字符串或字符串数组。如果请求方法匹配,则中间件将不会运行。

    • - path 它可以是字符串,正则表达式或其中任何一个的数组。如果请求路径匹配,则中间件将不会运行。

    • - ext 它可以是一个字符串或字符串数组。如果请求路径以这些扩展名之一结尾,则中间件将不会运行。

    • - custom 它必须是一个返回 true/ 的函数 false。如果函数针对给定的请求返回 true,则中间件将不会运行。该功能将通过 this 访问 Koa 的上下文

    • - useOriginalUrl 应该为 true 或 false,默认为 true。如果为false,path 则匹配 this.url 而不是 this.originalUrl。

    比如在custom 配置自定义函数进行判断。这个实现肯定很补科学,对于超多模块鉴权,这个custom岂不是超级复杂。比如:https://github.com/ppap6/PPAP.server/blob/master/app.js

     koa-jwt 中间件简化验证

    分模块鉴权:

    module.exports = (app) => {
        app.use(login.routes());
        app.use(koaJwt({
            secret: Const.TokenGlobal
        }).unless({ // 配置白名单
            method: 'get',
            path: [
                /\/api\/img/
            ]
        })).use(admin.routes());
    }

    模块里面在分路径鉴权:

    router
        .get('/', ctx => {
            ctx.type = 'html';
            ctx.body = fs.createReadStream('./public/index.html');
        })
        .get('/sign', ctx => {
            let payload = {name: 'morilence'};
            const token = jwt.sign(payload, 'fgnb', {
                notBefore: 30,
                expiresIn: 90
            });
            ctx.type = 'json';
            ctx.body = {
                token
            };
        })
        /* 只需把koaJwt中间件写在涉及具体业务逻辑处理的中间件之前就ok啦! */
        .get('/api', koaJwt({secret: 'fgnb'}), ctx => { // 参数对象指定密钥
            ctx.type = 'json';
            ctx.body = {
                msg: '你追我,如果你追到我,我就让你...'
            };
        })



    整个工程配置可以参看:https://github.com/zhoulujun008/koa-pass-server


    需要特别注意的是,需要http 请求增加 token认证。比如axios:

    http.interceptors.request.use((_config: any) => {
      const config = _config;
      if (!config) {
        return null;
      }
      removePendingRequest(config); // 检查是否存在重复请求,若存在则取消已发的请求
      addPendingRequest(config); // 把当前请求添加到pendingRequest对象中
      config.headers["X-Requested-With"] = "XMLHttpRequest";
      const token = localStorage.getItem("token");
      // config.url = 'http://local.zhoulujun.net:3000'+config.url
      // config.headers.common["Authorization"] = "Bearer " + token; // 留意这里的 Authorization
      config.headers["Authorization"] = "Bearer " + token; // 留意这里的 Authorization
      return config;
    }, (error) => {
      return Promise.reject(error);
    });

     config.headers["Authorization"] = "Bearer " + token; // 留意这里的 Authorization 这个一定不能少。


    参看文章:

    11.koa鉴权 https://juejin.cn/post/6896832791816880136

    【Koa】利用 JWT 实现 token验证 https://blog.csdn.net/Morilence/article/details/104301904




    转载本站文章《koa网站安全之JWT鉴权详解:koa-router与koa-jwt分模块鉴权实》,
    请注明出处:https://www.zhoulujun.cn/html/webfront/server/koa/8818.html