node.js和express.js中基于组/规则的授权方法

时间:2012-02-22 10:24:33

标签: node.js authorization express

express.js中基于角色的授权有哪些好的策略?特别是快递资源?

Express-resource没有处理程序,所以我认为有三种选择:

  1. 使用中间件
  2. 将授权功能传递给资源并单独检查每个资源请求
  3. 在身份验证后立即检查每个请求的授权
  4. 还有其他解决方案吗?

    组/基于角色的授权是一种非常古老的方法。是否有更新的访问控制方法?如果没有,基于角色的授权如何应用于node.js?存储组规则关系的位置(使用NoSQL / CouchDB / Redis)?

    例如,结构:

    /
      /forums
        /forums/threads
    

    每个资源都有索引,新建,创建,显示,编辑更新和销毁。有些人可以编辑/删除线程和论坛,有些人不应该。

6 个答案:

答案 0 :(得分:32)

我想说使用express-resource以干净的方式解决这个问题很困难,因为它不允许特定于路由的中间件(至少不是以干净的方式)。

我会选择类似于快递资源模块的布局,但是使用普通旧快递来路由它。像这样:

// Resource
var forum = {
  index: // ...
  show: // ...
  create: // ...
  update: // ...
  destroy: // ...
};

// Middleware
var requireRole = function(role) {
  return function(req, res, next) {
    if('user' in req.session && req.session.user.role === role)
      next();
    else
      res.send(403);
  }
};

// Routing
app.get('/forums', forum.index);
app.get('/forums/:id', forum.show);
app.post('/forums', requireRole('moderator'), forum.create); // Only moderators can create forums
app.delete('/forums/:id', requireRole('admin'), forum.destroy); // Only admins can delete forums

更新:目前正在进行关于快递资源中特定于路由的中间件的讨论,例如here。流行的观点似乎是每个动作都有一个数组,例如:

var forums = {
  index: [ requireRole('foo'), function(req, res, next) { ... } ]
};

您可以查看拉取请求,看看是否有任何可以使用的内容。当然,如果你对此感到不舒服,我完全理解它。我很确定我们将来会在快递资源中看到类似的内容。

我能想到的唯一其他解决方案就是Jan Jongboom的答案,即使用快速资源安装资源,但在其外部附加中间件,如:

app.delete('*', requireRole('admin')); // Only admins are allowed to delete anything
app.put('/forums/*', requireRole('moderator')); // Only moderators are allowed to update forums

但我很遗憾这会在整个地方泄露网址。

答案 1 :(得分:27)

我一直在研究同样的问题,并且遇到了一些好的模块。我一直专注于可以在这里找到的node-acl包。 https://github.com/optimalbits/node_acl

这个软件包似乎以一种非常容易理解的方式实现了ACL模式,并提供了将其轻松集成到节点/表达应用程序中的方法。

首先,您需要定义资源,角色和权限。

例如,资源可以是:

/
  /forums
    /forums/threads

角色可以是

public
admin
user
   john
   jane

在此示例中,john和jane角色可以映射到实际的用户帐户,但是它们将继承用户角色的所有权限。

资源上的权限

  • 创建
  • show
  • 更新
  • 破坏

或您的标准CRUD操作。

现在已经定义了这些,我们可以看一下使用node-acl设置acl的样子。这些说明来自文档

导入包

var acl = require('acl');

设置后端。我的应用程序正在使用mongodb,但node-acl包确实支持其他存储机制

acl = new acl(new acl.mongodbBackend(dbInstance, prefix));

我的应用程序正在使用mongoose,因此dbInstance将替换为mongoose.connection.db

现在让我们将我们的角色添加到ACL中。在node-acl中,通过赋予角色权限来创建角色。它就像用一块石头杀死两只鸟(实际上没有鸟类受到伤害)

acl.allow('admin', ['/', '/forum', '/forum/threads'], '*');
acl.allow('public', ['/', '/forum', '/forum/threads'], 'show');
acl.allow('user', ['/', '/forum', '/forum/threads'], ['create', 'show']);

让我们假设john创建了一个新资源,我们将添加一条新记录,允许john更新和删除该资源。

acl.allow('john', ['/forum/threads/abc123'], ['update', 'delete']);

我的应用程序也使用快递,所以我将使用路由中间件方法来检查路由。在我的路由配置中,我会添加行

在大多数快递配置中,这看起来像是pos

app.post('/', acl.middleware(), function(req, res, next) {...});
app.post('/forums', acl.middleware(), function(req, res, next) {...});
app.post('/forums/:forumId', acl.middleware(), function(req, res, next) {...});
app.post('/forums/threads', acl.middleware(), function(req, res, next) {...});
app.post('/forums/threads/:threadId', acl.middleware(), function(req, res, next) {...});

当没有传递参数时,这将检查req.userId中定义的角色是否允许在标识的资源上执行http方法,但是路径。

在这个例子中,http方法是post,但是对于你的配置中识别的每个http,它都会做同样的事情。

这提出了一个关于前面定义的权限的问题。要回答这些问题,我们必须从

更改权限
  • 创建
  • show
  • 更新
  • 破坏

传统

  • 获得
  • 删除

虽然此示例显示了所有硬编码的内容,但更好的做法是为您的权限设置管理界面,以便动态创建,读取,更新和删除它们,而无需修改代码。

我喜欢node-acl插件方法,因为它允许使用非常直接且灵活的api进行非常精细的权限角色分配。他们的文档中还有很多内容,我的示例显示我使用的是包。

希望这有帮助。

答案 2 :(得分:12)

Connect-roles非常好,简单,文档也很清晰。

var user = roles;

app.get('/profile/:id', user.can('edit profile'), function (req, res) {
  req.render('profile-edit', { id: req.params.id }); 
})
app.get('/admin', user.is('admin'), function (req, res) {
  res.render('admin');
}

答案 3 :(得分:3)

在express中,您可以添加一个挂钩到每个操作符(http://expressjs.com/guide.html#passing-route控件)的处理程序,您可以在其中进行前置条件验证。在这里,您可以检索用户的角色,并根据HTTP动词(PUT,DELETE等)或URL(param('op')是'edit'等)限制访问。

app.all('/user/:id/:op?', function(req, res, next){
  req.user = users[req.params.id];
  if (req.user) {
    next();
  } else {
    next(new Error('cannot find user ' + req.params.id));
  }
});

答案 4 :(得分:2)

我写了一个模块作为非显式路由中间件。适用于快速路线。

Gandalf on GitHub

答案 5 :(得分:0)

您可以尝试Casbin:https://casbin.org/,它具有Node.js版本。它还具有一个称为express-authz的Express.js中间件:https://casbin.org/docs/en/middlewares