将多范围 (ACL) 中间件传递给路由仅测试第一个范围

Passing multiple scope (ACL) middlewares to routes are only testing for the first scope

我的应用程序应该有 3 个用户范围(用户、管理员、超级管理员)。我试图在不使用任何外部 ACL 库的情况下手动执行此操作。

这是我的管理员和超级管理员范围的功能。

const adminScope = (req, res, next) => {
    if (req.user.scope !== 'admin') {
        return res.status(403).send({
            status: 'fail',
            message: 'You are not admin'
        })
    }
    next();
}


const superAdminScope = (req, res, next) => {
    if (req.user.scope !== 'superAdmin') {
        return res.status(403).send({
            status: 'fail',
            message: 'You are not Super Admin'
        })
    }
    next();
}

我正在尝试将这些与我的路线一起使用,如下所示

app.use('/admin', [passport.authenticate('jwt', { session: false }), adminScope], [adminPage])

以上工作正常并检查用户范围是否为 admin

我希望管理员和超级管理员都可以访问 adminPages 中的所有路由。

我尝试将 superAdminScope 作为第三个中间件传递。

app.use('/admin', [passport.authenticate('jwt', { session: false }), adminScope, superAdminScope], [adminPage])

仅检查 adminScope 函数后失败并显示

{
  status: "fail",
  message: "You are not admin"
}

我也试过将它们作为数组传递,但输出仍然相同。

app.use('/admin', [passport.authenticate('jwt', { session: false }), [adminScope, superAdminScope]], [adminPage])

使用 this 教程解决了它。

我没有为 adminsuperAdmin 使用单独的函数,而是创建了一个函数来检查它。

const checkForScope = (...scopes) => (req, res, next) => {
    if (!req.user) {
        return res.status(403).send({
            status: 'fail',
            message: 'You are not logged in'
        })
    }

    const hasScope = scopes.find(scope => req.user.scope === scope)

    if (!hasScope) {
        return res.status(403).send({
            status: 'fail',
            message: 'You dont have the rights to do this'
        })
    }

    return next();
}

然后我就可以在express中使用这个函数作为中间件了。

app.use('/admin', [passport.authenticate('jwt', { session: false }), checkForScope('admin', 'superAdmin')], [adminPage])

这将只允许用户访问具有 adminsuperAdmin 范围的路由。

我不确定这是否是最好的方法,但它确实有效。