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

express.js中,基于angular色的授权有什么好策略? 特别是与快递资源?

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

  1. 使用中间件
  2. 将授权函数传递给资源并分别检查每个资源请求
  3. 在authentication之后立即检查每个请求的授权

还有其他解决scheme吗?

集团/基于angular色的授权是一个非常古老的方法。 有更新的访问控制方法吗? 如果没有,那么如何将基于angular色的授权应用于node.js? 在哪里存储组规则关系(使用NoSQL / CouchDB / Redis)?

作为一个例子,结构:

/ /forums /forums/threads 

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

       

网上收集的解决方案 "node.js和express.js中基于组/规则的授权方法"

连接angular色相当不错,简单,文档也很清晰。

 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'); } 

我会说,使用快速资源很难以干净的方式解决这个问题,因为它不允许使用特定于路由的中间件(至less不是干净的方式)。

我会select一个类似于快速资源模块的布局,但是可以用简单的老式快车进行布线。 像这样的东西:

 // 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 

更新:关于快速资源中的特定路由中间件的讨论一直在进行,例如这里 。 stream行的观点似乎是每个行动都有一个数组,例如:

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

你可以看看拉请求,看看有没有什么可以使用的。 我完全理解,当然,如果你觉得不舒服。 我很确定将来会在快递资源中看到类似的情况。

我能想到的唯一的另一个解决scheme就是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 

但是,我很遗憾,这泄漏到所有地方的URL。

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

这个包似乎已经以一种非常容易理解的方式实现了ACL模式,并提供了方便的将它集成到您​​的节点/快速应用程序中的方法。

首先,你要定义你的资源,angular色和权限。

例如,资源可以是:

 / /forums /forums/threads 

angular色可以是

 public admin user john jane 

在这个例子中,angular色john和jane可以映射到实际的用户帐户,但是他们将inheritance用户angular色的所有权限。

资源的权限

  • 创build
  • 显示
  • 更新
  • 破坏

或者你的标准CRUD操作。

现在已经定义好了,我们可以看看如何使用node-acl设置acl。 这些说明来源于文档

导入包

 var acl = require('acl'); 

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

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

我的应用程序正在使用mongoose,所以dbInstance将被replace为mongoose.connection.db

现在让我们将angular色添加到ACL。 在node-acl中,通过给予angular色权限来创buildangular色。 它就像一石二鸟一样(没有鸟实际上受到伤害)

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

让我们假设一个新的资源是由john创build的,我们将添加一个新的logging,允许john也更新和删除该资源。

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

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

在大多数快速configuration中,这看起来像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) {...}); 

当没有parameter passing时,这将检查在req.userId中定义的angular色是否被允许在标识的资源上执行http方法,但是路由。

在这个例子中,http方法是post方法,但是它会为你的configuration中每个http标识符做同样的事情。

这提出了一个关于前面定义的权限的问题。 要回答这些问题,我们将不得不从更改权限

  • 创build
  • 显示
  • 更新
  • 破坏

给传统的

  • 岗位
  • 得到
  • 删除

尽pipe这个例子显示了硬编码的一切,但更好的做法是为您的权限设置一个pipe理界面,以便dynamic地创build,读取,更新和删除它们,而无需修改代码。

我喜欢node-acl插件方法,因为它允许使用非常直接和灵活的api来进行非常细微的权限angular色分配。 在他们的文档中有很多,我的例子显示了我的包装。

希望这有助于。

在expression式中,您可以添加一个处理程序,该程序可以挂接到每个运算符(http://expressjs.com/guide.html#passing-route控件),您可以在其中进行预处理validation。 在这里,您可以检索用户的angular色,并根据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)); } }); 

我写了一个模块作为非显式路由中间件。 与快递路线工作良好。

在GitHub上的Gandalf