node.js 和 express.js 中基于组/规则的授权方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9392978/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Group/rule-based authorization approach in node.js and express.js
提问by Patrick
What are good strategies for role-based authorization in express.js? Especially with express-resource?
express.js 中基于角色的授权有哪些好的策略?尤其是快递资源?
With Express-resourcethere are no handlers, so I think there are three options:
使用Express-resource没有处理程序,所以我认为有三种选择:
- Use a middleware
- Pass the authorization function to the resource and check each resource request separately
- Check authorization with every request right after authentication
- 使用中间件
- 将授权函数传递给资源,分别检查每个资源请求
- 验证后立即检查每个请求的授权
Are there any other solutions?
还有其他解决方案吗?
Group/Role-based authorization is a pretty antique approach. Are there newer methods of access control? If not, how can role-based authorization be applied to node.js? Where to store group-rule relationships (with NoSQL/CouchDB/Redis)?
基于组/角色的授权是一种非常古老的方法。是否有更新的访问控制方法?如果不是,如何将基于角色的授权应用于 node.js?在哪里存储组规则关系(使用 NoSQL/CouchDB/Redis)?
As an example, the structure:
例如,结构:
/
/forums
/forums/threads
Each resource with index, new, create, show, edit update and destroy. Some people can edit/delete etc. threads and forums, some people shouldn't.
每个资源都带有索引、新建、创建、显示、编辑更新和销毁。有些人可以编辑/删除等主题和论坛,有些人不应该。
采纳答案by xinbenlv
Connect-rolesis quite good, simple and the documentation is also very clear.
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');
}
回答by Linus Gustav Larsson Thiel
I would say that it's hard to solve this in a clean manner using express-resource, since it doesn't allow for route-specific middleware (at least not in a clean way).
我会说很难使用 express-resource 以干净的方式解决这个问题,因为它不允许特定于路由的中间件(至少不是以干净的方式)。
I would opt for a similar layout as an express-resource module, but route it with plain old express. Something like this:
我会选择与 express-resource 模块类似的布局,但使用普通的 express 路由它。像这样的东西:
// 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
UPDATE:There have been ongoing discussions regarding route-specific middleware in express-resource, e.g. here. The prevailing view seems to be to have an array per action, e.g.:
更新:一直在讨论关于 express-resource 中特定于路由的中间件,例如这里。普遍的观点似乎是每个动作都有一个数组,例如:
var forums = {
index: [ requireRole('foo'), function(req, res, next) { ... } ]
};
You could take a look through the pull requests and see if there is anything you could use. I totally understand it, of course, if you don't feel comfortable with that. I'm pretty sure we will see something like this in express-resource in the future.
您可以查看拉取请求,看看是否有任何您可以使用的东西。当然,如果您对此感到不舒服,我完全理解。我很确定我们将来会在 express-resource 中看到类似的东西。
The only other solution I can think of is along the lines of Jan Jongboom's answer, which would be to mount the resources with express-resource, but have middleware attached "outside" of that, something like:
我能想到的唯一其他解决方案是按照 Jan Jongboom 的回答,这将是使用 express-resource 安装资源,但将中间件附加到“外部”,例如:
app.delete('*', requireRole('admin')); // Only admins are allowed to delete anything
app.put('/forums/*', requireRole('moderator')); // Only moderators are allowed to update forums
But I regret that this leaks URLs all over the place.
但我很遗憾这会到处泄露 URL。
回答by Isioma Nnodum
I have been researching the same question and have come across a few good modules. I have been focusing on the node-acl package that can be found here. https://github.com/optimalbits/node_acl.
我一直在研究同样的问题,并遇到了一些很好的模块。我一直专注于可以在这里找到的 node-acl 包。https://github.com/optimalbits/node_acl。
This package seems to have implemented the ACL pattern in a very understandable way and has provided ways to easily integrate it into your node/express application.
这个包似乎以一种非常易于理解的方式实现了 ACL 模式,并提供了将其轻松集成到您的节点/express 应用程序中的方法。
Firstly, you'll want to define your resources, roles, and permissions.
首先,您需要定义资源、角色和权限。
For example, the resources can be:
例如,资源可以是:
/
/forums
/forums/threads
The roles can be
角色可以是
public
admin
user
john
jane
In this example, the roles john and jane can map to actual user accounts, but they will inherit all the permissions of the user role.
在此示例中,角色 john 和 jane 可以映射到实际用户帐户,但它们将继承用户角色的所有权限。
The permissions on the resources
资源的权限
- create
- show
- update
- destroy
- 创建
- 展示
- 更新
- 破坏
Or your standard CRUD operations.
或者您的标准 CRUD 操作。
Now that those have been defined, we can take a look at how it would look to set up the acl using node-acl. These notes are derived from the documentation
现在已经定义了这些,我们可以看看如何使用 node-acl 设置 acl。这些注释来自文档
import the package
导入包
var acl = require('acl');
Set up your backend. My app is using mongodb, but the node-acl package does support other storage mechanisms
设置你的后端。我的应用程序使用的是 mongodb,但 node-acl 包确实支持其他存储机制
acl = new acl(new acl.mongodbBackend(dbInstance, prefix));
My app is using mongoose so dbInstance would be replaced with mongoose.connection.db
我的应用程序正在使用猫鼬,因此 dbInstance 将替换为 mongoose.connection.db
Now lets add our roles to the ACL. In node-acl, roles are created by giving them permissions. Its like killing two birds with one stone (no birds are actually harmed)
现在让我们将我们的角色添加到 ACL。在 node-acl 中,角色是通过授予权限来创建的。就像一石激起两只鸟(实际上没有鸟受到伤害)
acl.allow('admin', ['/', '/forum', '/forum/threads'], '*');
acl.allow('public', ['/', '/forum', '/forum/threads'], 'show');
acl.allow('user', ['/', '/forum', '/forum/threads'], ['create', 'show']);
Lets assume a new resource is created by john, we will add a new record that allows john to also update and delete that resource.
假设 john 创建了一个新资源,我们将添加一条新记录,允许 john 更新和删除该资源。
acl.allow('john', ['/forum/threads/abc123'], ['update', 'delete']);
My application is also using express, so I will use the routing middleware approach to check routes. In my routing configuration, I would add the line
我的应用程序也在使用 express,所以我将使用路由中间件方法来检查路由。在我的路由配置中,我会添加该行
In most express configurations, this looks like for the pos
在大多数快速配置中,这看起来像 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) {...});
When no parameters are passed, this will check if the role defined in req.userId is allowed to execute the http method on the resource identified but the route.
当没有传递参数时,这将检查是否允许在 req.userId 中定义的角色对标识的资源执行 http 方法,但路由。
In this example the http method is post, but it will do the same thing for each http idenitified in your configuration.
在这个例子中,http 方法是 post,但它会对配置中的每个 http 标识做同样的事情。
This raises the question, about the permissions defined earlier. To answer those questions, we would have to change the permissions from
这就提出了一个问题,关于之前定义的权限。要回答这些问题,我们必须将权限从
- create
- show
- update
- destroy
- 创建
- 展示
- 更新
- 破坏
To the conventional
对常规
- post
- get
- put
- delete
- 邮政
- 得到
- 放
- 删除
Although this example shows everything hardcoded, the better practice is to have a management interface for your permissions so they can be created, read, updated, and deleted dynamically without having to modify your code.
尽管此示例显示了所有硬编码,但更好的做法是为您的权限设置一个管理界面,以便可以动态创建、读取、更新和删除它们,而无需修改您的代码。
I like the node-acl plugins approach as it allows for very fine grained permission-role assignments using a very straight forward and flexible api. There is a lot more in their documentation, my example shows were I am with the package.
我喜欢 node-acl 插件方法,因为它允许使用非常直接和灵活的 api 进行非常细粒度的权限角色分配。他们的文档中有更多内容,我的示例显示我使用了该软件包。
Hopefully this helps.
希望这会有所帮助。
回答by Jan Jongboom
In express you can add a handler that hooks into every operator (http://expressjs.com/guide.html#passing-route control) where you can do precondition validation. Here you can retrieve the role for the user and restrict access based on the HTTP verb (PUT, DELETE, etc.) or the URL (param('op')is 'edit' or so).
在 express 中,您可以添加一个挂钩到每个操作符(http://expressjs.com/guide.html#passing-route 控件)的处理程序,您可以在其中进行前提条件验证。在这里,您可以检索用户的角色并根据 HTTP 动词(PUT、DELETE 等)或 URL(例如param('op')“编辑”等)限制访问。
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));
}
});
回答by Patrick
I wrote a module as non-explicit routing middleware. Works well with express-routes.
我写了一个模块作为非显式路由中间件。适用于快速路线。
回答by Yang Luo
You can try Casbin: https://casbin.org/, it has a Node.js version. It also has a Express.js middleware called express-authz: https://casbin.org/docs/en/middlewares
你可以试试 Casbin: https://casbin.org/,它有一个 Node.js 版本。它还有一个 Express.js 中间件,称为express-authz:https: //casbin.org/docs/en/middlewares

