【问题标题】:how to access db from node.js middleware如何从 node.js 中间件访问数据库
【发布时间】:2015-11-21 19:06:31
【问题描述】:

我想验证用户是否具有允许他/她在我的 API 中使用端点的角色。通常我会通过将 userId 作为 JWT 的一部分发送并在 DB 上查找以查看用户的角色来这样做。它会在 API 调用中发生,看起来像这样:

var userId = getUserIdFromJwt();

app.models.User.findOne({_id: userId}, function (err, user) {
    ...check if user is in role...
});

现在我想尝试将该代码移动到一个中间件,如下所示:

exports.isUserInRole = function(app, allowableRoles) {
    var userId = getUserIdFromJwt();

    app.models.User.findOne({_id: userId}, function (error, user) {
        if (error) {
            return res.status(500).json(error);
        }

        return function (req, res, next) {
            if(_.includes(allowableRoles, user.Role)) {
                next();
            } else {
                return res.status(401).json({"error": "User not in role"});
            }
        }
    });
};

中间件的实现方式如下:

const allowableRoles = ['admin', 'implementor'];
app.get('/getStuff/', isUserInRole(app, allowableRoles), function (req, res) {
   ... do stuff if user is in role ...
});

此时我遇到了app.models.User 值始终为undefined 的问题。

我不明白为什么此时 app.models.User 未定义,因为我可以在 get 调用中的匿名函数中访问它。

如果我无法发送app.models.User,我将如何从我的中间件中访问数据库?

作为参考,我正在使用 Mongoose 并将其暴露给我访问 MongoDB 数据库的 server.js 中的应用程序。

【问题讨论】:

  • 为了我理解正确,app.models.UserisUserInRole 之后或期间调用的函数中是否未定义?
  • app.models.User.findOne 是未定义的吗?
  • app.models.UserisUserInRole 被调用为中间件的那一刻是未定义的,但它在下一个函数中可用。例如,如果我将isUserInRole 作为中间件并将其作为匿名函数中的普通函数调用,那么我可以看到调用了数据库,因为app.models.User 不是未定义的。

标签: node.js mongodb express mongoose middleware


【解决方案1】:

我认为您的问题是您试图在模型实际初始化之前获取模型,因为您将应用程序绑定到应用程序初始化的参数。

所以在您的主应用程序文件中,我会执行 module.exports = app;,然后在您的中间件文件中,只需执行 var app = require('./path/to/app'); 即可包含该应用程序。然后从中间件中删除app。你可能会得到这样的结果:

var app = require('./path/to/app');

exports.isUserInRole = function(allowableRoles) {};

并在您的路线中将其更改为:

const allowableRoles = ['admin', 'implementor'];
app.get('/getStuff/', isUserInRole(allowableRoles), function (req, res) {}

最后在您的应用文件中,将应用添加到导出:

module.exports = app;

编辑:

如果您使用的是 Mongoose,您还可以执行以下更简单的操作:

var mongoose = require('mongoose');
var User = mongoose.model('User');

【讨论】:

    【解决方案2】:

    我的第一个猜测是 b/c 你实际上是在调用函数而不是仅仅将它传入。此外,你实际上并没有传入中间件。中间件函数看起来像

    function(req,res,next){}
    

    此外,您可能希望利用会话而不是每次请求都访问数据库

    【讨论】:

    • 我认为使用会话不一定是正确的方法。我宁愿保持 API 无状态。这就是我选择使用 JWT 的原因。我可以将用户的角色添加到 JWT 有效负载中,但我觉得这是不安全的,因为我不能信任用户发回的任何内容 - 除非我使用 ssl,我不想在开发期间这样做。不信任用户是为什么我需要检查他/她拥有哪些权限才能决定是否继续,并且一个简单的数据库调用并不太贵,是吗? (我应该通过指定要返回的列而不是像现在一样返回所有列来降低成本。)
    • @MrThursday 您仍然可以使用会话并保持后端无状态。你是对的,你不应该接受来自客户端的权限,这真的很糟糕。但是,您可以执行一次 db 调用,然后将它们的权限存储在服务器端会话变量中,这样您就不必在下一个请求时访问 db。显然,您必须管理会话,包括处理修改用户角色时的情况。不过,这无关紧要,我认为您真正的问题是您实际上并未将授权调用编写为中间件。
    猜你喜欢
    • 1970-01-01
    • 2019-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-05
    • 2022-01-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多