Express.js中间件额外(第四)参数

时间:2016-11-04 01:24:52

标签: javascript node.js express middleware

在Express.js中间件的可选参数上,除了是一个错误处理中间件之外,可能是第四个,我有一个有用的用例。它可以通过不同的方式实现,但无论如何。

我想要检查一些api路由权限,我想写的中间件应该为请求用户查找他/她有多少信誉点(整数)的数据库。我定义了一个对象来保存作为键值对所需的特权和信誉点。之后,中间件应查找此权限对象,以查看用户是否具有相应操作的信誉点数大于或等于。我想将这个相应的操作名称作为每个路由的不同字符串传递给特权对象中的一个键。这可以通过请求发送到路由的字符串actionName来实现,但我发现它不太安全(请求中的数据可能被篡改为具有恶意用户可访问的操作名称并具有所需数据另一个希望但不允许采取行动的领域。)

所有情况都与SE的情况相同。

顺便说一句,显然我还需要基于路由(不是基于路由器)的中间件安装,我不确定Express.js是否支持,但这是另一个故事。

也许有人可以描述并问这个用例为我可以用我的参数参数化中间件函数,而不仅仅是传入的req和res对象吗?

如何使用Express.js中间件实现此用例?或者我应该使用其他机制吗?

/// Privilege Check middleware
// used per route with corresponding actionName
// signature function (request, response, next, actionNameOneOfKeysInPrevilegesObject::String)
var privilegeCheck = function (req, res, next, actionName) {
    db.one(
        `
            SELECT reputation FROM users WHERE id = $(id)
        `,
        {id: req.user.id} // remember req.user was set by jwt.sign(data) during login or signup with demanded data; here it is {id:, name:, username:,}
    )
        .then(function (data) {
            if(data >= privileges[actionName]) {
                next();
            }
            else {
                res.status(403).json({errorMessage: "You need to have " + privileges.questionUpvote + " reputation to upvote."});
            }
        })
        .catch(function (error) {
            console.error(error);
        })
};

// reputations needed for privileged actions
var privileges =
{
    questionAsk: 5,
    answer: 15,
    acceptAnswer: 0,
    comment: 5,
    questionEdit: 20,
    answerEdit: 20,
    commentsEdit: 0,
    postsUpvote: 30,
    postsDownvote: 30,
    commentsUpvote: 5,
    questionUpvote: 10,
    questionDownvote: 125,
}

2 个答案:

答案 0 :(得分:5)

使用特定于路由的中间件:

function privilegeCheck(actionName) {
    return function (req, res, next) {
        db.one(
            `
                SELECT reputation FROM users WHERE id = $(id)
            `,
            {id: req.user.id} // remember req.user was set by jwt.sign(data) during login or signup with demanded data; here it is {id:, name:, username:,}
        )
            .then(function (data) {
                if(data >= privileges[actionName]) {
                    next();
                }
                else {
                    res.status(403).json({errorMessage: "You need to have " + privileges.questionUpvote + " reputation to upvote."});
                }
            })
            .catch(function (error) {
                console.error(error);
            })
        ;
    }
};

// Then, for each of your routes, invoke your privilegeCheck() function
// as an "in-between" argument between your path and your route handler 
// function.

app.get('/my/route', privilegeCheck("myActionName"), (req, res) => {
    res.status(200).send('handled /my/route');
});

参见"应用程序级中间件" http://expressjs.com/en/guide/using-middleware.html处的部分,从&#34开始;此示例显示了一个中间件子堆栈,用于处理对/ user /:id路径的GET请求。" 但是那里的文档没有显示你可以在app.get()中链接函数。你可以在

看到

https://scotch.io/tutorials/route-middleware-to-check-if-a-user-is-authenticated-in-node-js

事实上,你可以拥有尽可能多的中间件" (即三参数函数)根据需要对任何Express的路由处理函数(get(),put(),post(),delete())进行参数。

答案 1 :(得分:0)

不幸的是,Express已编码,因此如果您的中间件函数只有四个参数,则将其视为错误处理中间件。 IMO这不是一个好的设计决定。

要做你想做的事,规范的方法是将数据附加到请求流(req)。

例如:

app.use(function(req,res,next){
    req.data = {foo:'bar'};

});


app.use(function(req,res,next){
  const data = req.data;
}):

来自像Java这样的语言,我认为这是有史以来最疯狂的编码,但它起作用,因为req对于该请求是唯一的+ JS是单线程"。