Koa-router 在到达路由之前获取已解析的参数

Koa-router getting parsed params before hitting route

我在上面使用 koa2 和 koa-router 以及 sequelize。我希望能够根据用户在数据库中的角色来控制用户访问权限,到目前为止,它一直在工作。我做了自己的 RBAC 实现,但遇到了一些问题。

考虑到端点可以执行任何操作(如插入新项目等),如果用户无权访问,我需要在命中任何端点之前退出执行。这很有意义,我意识到我可能会使用 Sequelize 的事务,但我发现这会增加更多的开销并且截止日期即将结束。

到目前为止,我的实现看起来有点像下面这样:

// initialize.js

initalizeRoutes()
initializeServerMiddleware()

服务器中间件在路由之后注册。

// function initializeRoutes
app.router = require('koa-router')

app.router.use('*', access_control(app))

require('./routes_init')

routes_init 只是运行一个递归解析文件夹并导入所有中间件定义的函数。

// function initializeServerMiddleware
// blah blah bunch of middleware
app.server.use(app.router.routes()).use(app.router.allowedMethods())

这只是普通的 koa-router。

然而,问题出现在access_control。

我有一个文件 (access_control_definitions.js),我在其中指定命名路由、它们各自的续集模型名称以及路由存在的规则。 (例如,什么角色,如果所有者能够访问他们自己的资源......)我通过路由参数计算请求者是否拥有资源(例如资源 ID 是 ctx.params.id)。然而,在这个实现中,params 似乎没有被解析。我认为我必须在 koa-router 执行之前手动解析参数是不对的。是否有人能够基于此确定更好的方法来解决 ctx.params 未填充实际命名参数的问题?

编辑:I also created a GitHub issue for this,考虑到在我看来似乎发生了一些有趣的事情。

所以如果你看 router.js

layerChain = matchedLayers.reduce(function(memo, layer) {
  memo.push(function(ctx, next) {
    ctx.captures = layer.captures(path, ctx.captures);
    ctx.params = layer.params(path, ctx.captures, ctx.params);
    ctx.routerName = layer.name;
    return next();
  });
  return memo.concat(layer.stack);
}, []);

return compose(layerChain)(ctx, next);

它所做的是,对于您拥有的每个路由函数,它都会添加自己的捕获层来生成参数

现在这确实有意义,因为您可以为相同的 url 使用不同参数的两个中间件

router.use('/abc/:did', (ctx, next) => {
    // ctx.router available
    console.log('my request came here too', ctx.params.did)
    if (next)
        next();
});

router.get('/abc/:id', (ctx, next) => {
    console.log('my request came here', ctx.params.id)
});

现在对于第一个处理程序,参数 id 没有意义,对于第二个处理程序,参数 did 没有任何意义。这意味着这些参数特定于处理程序并且仅在处理程序内部有意义。这就是为什么没有你期望的参数是有意义的。我不认为这是一个错误

既然您已经找到了解决方法

const fromRouteId = pathToRegexp(ctx._matchedRoute).exec(ctx.captures[0])

你应该使用相同的。或者更好的可能是

var lastMatch = ctx.matched[ctx.matched.length-1];
params = lastMatch.params(ctx.originalUrl, lastMatch.captures(ctx.originalUrl), {})