首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >通过中间件检查多个权限

通过中间件检查多个权限
EN

Stack Overflow用户
提问于 2019-07-31 08:38:20
回答 1查看 507关注 0票数 3

我已经解决了这个问题。我找到Express.js role-based permissions middleware并使用它。太棒了,我会重写我的代码!

我想检查一下多个许可,但这对我没用。

我创建了三个检查传输的中间件:requiredAuthcheckAdmincheckCompanyManager

模型:User:{名称、许可、isBlocked、公司:{id,userPermistion}}

requiredAuth函数将检查并找到signedUser,并将其设置为res.locals.user

代码语言:javascript
复制
const checkAdmin = (req, res, next) => {
    let user = res.locals.user
    if (user.permission === 2) next()
    else res.json({errors: "Only admin can do this action"})
}

const checkCompanyManager = (req, res, next) => {
    let user = res.locals.user
    let companyId = req.body.companyId ? req.body.companyId : req.query.companyId
    if (user.company.id && user.company.id.equals(companyId)
        && user.company.userPermistion === 1) next()
    else res.json({errors: "Only company member can do this action"})
}

最后,我使用所有在路由器中检查动作块用户(只有管理员或公司经理可以阻止用户)。

代码语言:javascript
复制
router.post('/admin/block-by-ids',
    requiredAuth,
    checkAdmin || checkCompanyManager,
    userController.blockByIds
)

但是它不起作用,因为如果checkAdmin错了,就会中断并返回json,不能运行checkCompanyManager --我可以如下所示解决这个问题:

代码语言:javascript
复制
router.post('/admin/block-by-ids',
    requiredAuth,
    (req, res, next) => {
        let user = res.locals.user
        let companyId = req.body.companyId
        if ((user.permission === 2) ||
            (user.company.id && user.company.id.equals(companyId) &&
                user.company.userPermistion === 1)) {
            next()
        } else next("Only admin or company manager can do this action")
    },
    userController.blockByIds
)

但这不好玩!我只想使用中间件来检查,而不想再次编写代码。我该怎么做?我要你给我个主意!

EN

回答 1

Stack Overflow用户

发布于 2019-07-31 10:09:58

||操作符不执行您认为的操作。它返回第一个真实值:

代码语言:javascript
复制
var a = 1 || 2; // a is 1

您需要的是一个中间件。类似于:

代码语言:javascript
复制
function or (middleware1, middleware2) {
    return function (req, res, next) {
        var alreadyCalledNext = false;
        function resolve () {
            if (!alreadyCalledNext) {
                alreadyCalledNext = true;
                next();
            }
        }
        middleware1(req,res,resolve);
        middleware2(req,res,resolve);
    }        
}

router.post('/admin/block-by-ids',
    requiredAuth,
    or(checkAdmin, checkCompanyManager),
    userController.blockByIds
)

但是,上述实现遇到了另一个问题。一旦您发送了res.json,您就不能再发送另一个响应。因此,如果checkAdmincheckCompanyManager都失败了,则需要阻止它们发送res.json,除非两者都失败。因此,您需要对res进行存根,并传递一个假的res (就像我们对next所做的一样):

代码语言:javascript
复制
function or (middleware1, middleware2) {
    return function (req, res, next) {
        var alreadyCalledNext = false;
        function resolve () {
            if (!alreadyCalledNext) {
                alreadyCalledNext = true;
                next();
            }
        }
        var jsonCount = 0;
        var fakeRes = {
            locals: res.locals,
            json: function (data) {
                jsonCount ++;
                if (jsonCount >= 2) { // both must fail for OR to fail
                    res.json(data);
                }
            }
        }

        middleware1(req,fakeRes,resolve);
        middleware2(req,fakeRes,resolve);
    }        
}

这应该能行。

上面的解决方案感觉设计过度了.我会亲自使checkAdmincheckCompanyManager常规函数返回布尔值,然后将它们包装在checkPermissions中间件中:

代码语言:javascript
复制
const isAdmin = (req,res) => {
    let user = res.locals.user
    return user.permission === 2
}

const isCompanyManager = (req,res) => {
    let user = res.locals.user
    let companyId = req.body.companyId ? req.body.companyId : req.query.companyId
    return user.company.id && user.company.id.equals(companyId) && user.company.userPermistion === 1
}

const checkPermissions = function (checks) {
    return (req, res, next) => {
        // Call next if any check passes:
        for (let i=0; i<checks.length; i++) {
            if (checks[i](req,res)) return next();
        }

        res.json({errors: "You don't have authorization to do this action"})
    }
}

router.post('/admin/block-by-ids',
    requiredAuth,
    checkPermissions([isAdmin, isCompanyManager]),
    userController.blockByIds
)
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57286564

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档