koa-unless增加method限制

没事自己撸了个web项目,后端用的是koa2,并使用了koa-jwt进行鉴权,在使用的时候遇到了些小问题。

一、问题

用koa-jwt鉴权的时候,可以通过设置unless路径,使得某些api不用经过鉴权,比如登录接口:

app.use(jwtKoa({secret}).unless({
    path: [/^\/api\/login/]
}));

当然还有些比如获取文章内容接口,我需要在未登录时显示文章,修改和删除是需要鉴权,但由于使用了restful api设计,获取文章和删除文章的api路径是一样的,使用前面的这种方式无法区分get与delete请求,导致鉴权没有任何意义了。

看了下koa-jwt文档上,并没有我需要的,只能看下代码咯,毕竟,比文档更全面的就只有代码了。

二、处理问题

查看koa-jwt代码,发现unless匹配与验证这块是使用的koa-unless,在package.json中也可以看到:

《koa-unless增加method限制》

既然这样,我们就去查看koa-unless的文档,只能找到单一的url匹配和method匹配,并没有两者结合的判断方式。没办法,只能去看koa-unless的源码了。

koa-unless

koa-unless目录比较简单,源码就一个index.js,细看代码,

if (matchesCustom(ctx,opts) || matchesPath(requestedUrl,opts) ||
    matchesExtension(requestedUrl,opts) ||matchesMethod(ctx.method,opts)) {
    return next();
}

焦点到这个if判断上,此处就是在处理http请求的数据与unless函数是否匹配的地方,当能够匹配上时,则可以继续执行后面的函数。

function matchesPath(requestedUrl,opts) {
    // ...
}

matchesPath,该方法用于判断当前请求的url是否符合unless中的路径。

function matchesMethod(method,opts) {
    // ...
}

该方法用于判断当前请求方式是否在unless的允许范围内。

我们发现,这几个match匹配函数之间都是或运算符,因此只要任何一者满足,if就可以通过,所以,url与method之间并没有关系,因此,并没有我想要的功能。

小改以下

既然用||没有关联,改成&&是不是就可以了呢?

依旧不行,因为解析规则并没有改变,我没法给每个url增加独立的method。所以得大改一下了。

三、修改组件

我想要的功能是这样的,

app.use(jwtKoa({secret}).unless({
    method: ['POST'],path: [/^\/api\/login/,{url: /^\/api\/publicKey/,method: ['GET']}]
}));

path中可以像原先一样直接些路径的正则或者字符串,如果这么写了,他的method就由外侧与path同级的method控制(不写这个method,默认所有方法)。当然也可以在path中设置对象的方式规定url和method,这种方式中的method优先级更高。

考虑到路由多的情况下,在初始化的时候,将unless中的url与method解析到一个空对象之中,并以method为key值,而允许的路由则放在key对应的value数组中。这样,当请求的时候就不用整个unless遍历了。

// 请求方式
var methods = ['GET','POST','PUT','DELETE','OPTIONS','HEAD','TRACE','CONNECT'];
// 存储 method: [url1,url2 ...]
var map = {};

在初始化的时候,解析unless配置:

/**
 * 将用户写的unless配置转到map数据中
 * @param {Object} map 需要存储到的空对象
 * @param {Object} opts 填写的unless配置
 */
function filterUnless(map,opts) {
    // 处理不写外层method时,默认支持所有请求方式
    var mes = opts.method ? opts.method : methods;
    if (Array.isArray(opts.path)) {
        opts.path.forEach((item) => {
            var method = [],url='';
            if (Object.prototype.toString.call(item) === '[object Object]') {
                // path中的是对象的,则查找他的path和method
                url = item.url;
                method = item.method || mes;
            } else {
                // 单个字符串或正则
                url = item;
                method = mes;
            }
            // 记录
            record(map,method,url);
        });
    } else if (Array.isArray(opts.method)) {
        // 没有path,检测下是否有method
        opts.method.forEach((met) => {
            // 当方法后的value为空数组时,表示所有url均会符合
            map[ met.toLowerCase() ] = [];
        });
    }
}
// 将 key: ulr1记录到map中
function record(map,url) {
    method.forEach((met) => {
        if (!map[ met.toLowerCase() ]) {
            // 无值时,需要先创建空数组
            map[ met.toLowerCase() ] = [];
        }
        map[ met.toLowerCase() ].push(url);
    });
}

既然想要url和method能够相互关联,那么彼此之间肯定要有制约,那么将这两者的判断放到同个方法中。删掉if判断中的matchesPath()与matchesMethod()方法,增加matchesPathAndMethod()方法,参数是当前请求的url和请求方式method。

因为前面已经用map缓存了数据,所以后面的处理就会简单多了。

/**
 * 处理当前请求url和method是否符合unless中的配置
 * @param {Object} requestedUrl 请求url相关信息
 * @param {String} method 请求方式
 */
function matchesPathAndMethod(requestedUrl,method) {
    var path = requestedUrl.pathname,mets = map[ method.toLowerCase() ];
    if (!mets) {
        // 没这个方法
        return false;
    }
    if (!mets.length) {
        // 长度是0,证明所有请求都可以
        return true;
    }
    return mets.some(function (p) {
        return (typeof p === 'string' && p === path) ||
            (p instanceof RegExp && !!p.exec(path));
    });
}

对应method中没有url,则直接false,当对应method下是空数组,则是所有url都ok。其他情况下,则需要依次遍历method下的url是否匹配。

文件下载地址:koa-unless

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


这篇文章主要介绍“基于nodejs的ssh2怎么实现自动化部署”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“基于nodejs...
本文小编为大家详细介绍“nodejs怎么实现目录不存在自动创建”,内容详细,步骤清晰,细节处理妥当,希望这篇“nodejs怎么实现目录不存在自动创建”文章能帮助大...
这篇“如何把nodejs数据传到前端”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这...
本文小编为大家详细介绍“nodejs如何实现定时删除文件”,内容详细,步骤清晰,细节处理妥当,希望这篇“nodejs如何实现定时删除文件”文章能帮助大家解决疑惑...
这篇文章主要讲解了“nodejs安装模块卡住不动怎么解决”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来...
今天小编给大家分享一下如何检测nodejs有没有安装成功的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文...
本篇内容主要讲解“怎么安装Node.js的旧版本”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎...
这篇“node中的Express框架怎么安装使用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家...
这篇文章主要介绍“nodejs如何实现搜索引擎”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“nodejs如何实现搜索引擎...
这篇文章主要介绍“nodejs中间层如何设置”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“nodejs中间层如何设置”文...
这篇文章主要介绍“nodejs多线程怎么实现”,在日常操作中,相信很多人在nodejs多线程怎么实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法...
这篇文章主要讲解了“nodejs怎么分布式”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“nodejs怎么分布式”...
本篇内容介绍了“nodejs字符串怎么转换为数组”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情...
这篇文章主要介绍了nodejs如何运行在php服务器的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇nodejs如何运行在php服务器文章都...
本篇内容主要讲解“nodejs单线程如何处理事件”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“nodejs单线程如何...
这篇文章主要介绍“nodejs怎么安装ws模块”,在日常操作中,相信很多人在nodejs怎么安装ws模块问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法...
本篇内容介绍了“怎么打包nodejs代码”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!
本文小编为大家详细介绍“nodejs接收到的汉字乱码怎么解决”,内容详细,步骤清晰,细节处理妥当,希望这篇“nodejs接收到的汉字乱码怎么解决”文章能帮助大家解...
这篇“nodejs怎么同步删除文件”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇...
今天小编给大家分享一下nodejs怎么设置淘宝镜像的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希