MongoDB + 节点 JS + 基于角色的访问控制 (RBAC)
MongoDB + Node JS + Role Based Access Control (RBAC)
我目前正在学习 MEAN 堆栈,正在开发一个简单的 TODO 应用程序,并希望为此实现基于角色的访问控制 (RBAC)。我如何在 MongoDB 上设置角色和权限。
我想要3个角色(角色可能看起来很有趣,但这纯粹是为了学习):
- 上帝
- 超级英雄
- 男人
GOD - 类似于超级管理员,可以在应用程序中做任何事情。 TODO 和其他用户的 C、R、U、D 权限。可以创建一个 TODO 并将其直接分配给任何 SUPER HERO 或 MAN。随时更新或删除 TODO 或用户。
SUPER HERO - 类似于管理员,拥有对个人数据执行任何操作的超能力 - C、R、U、D 用于 TODO。无法创建任何用户。只能阅读和添加由 GOD 创建并分配给 him/her.
的 TODO 的评论
MAN - 只能阅读分配给 him/her 的 TODO 并添加评论。
总结一下:
GOD - C,R,U,D [Global Level]
SUPER HERO - C,R,U,D [Private] + R,U [Assigned to him]
MAN - R,U [Assigned to him]
我知道我需要有 USERS & ROLES 集合。 ROLES 反过来应该有 PERMISSIONS 等。我如何连接它们?
可能的方法-> 在用户中嵌入角色 collection/schema:
用户文档应包含以下内容:
{
_id : "email@mail.com",
name: "lorem ipsum",
role: "MAN"
}
据您的 post 描述,只有上帝才能制定和分配 TODO。
角色集合可能包含以下内容:
{
_id : "MAN",
globalPerm: [],
privatePerm: [],
assignedPerm: ["r","u"],
},
{
_id : "SUPER_HERO",
globalPerm: [],
privatePerm: ["c","r","u","d"],
assignedPerm: ["c","r","u","d"],
},
{
_id : "GOD",
globalPerm: ["c","r","u","d"],
privatePerm: ["c","r","u","d"],
assignedPerm: ["c","r","u","d"],
}
Node JS 中间件
在为用户获得正确的权限值后,您可能想要使用中间件。
示例快速 HTTP 请求路由:
app.post('/updateTodo', permissions.check('privatePerm', 'c'), function (req, res) {
// do stuff
};
permissions.check 在实际执行函数体之前调用以更新 TODO。
因此,如果用户尝试更新待办事项,它将首先验证相应的权限。
这是一个非常广泛的问题,可以通过多种方式解决。
您已经补充说您使用的是 MEAN 堆栈,因此我的问题仅限于此。
您没有在整个问题中包括的一件事是您使用的是哪种身份验证架构。假设您正在使用基于令牌的身份验证,如今人们通常都在使用它。
我们有 3 种类型的用户。
您也可以使用不同的选项来区分令牌类型。
- 不同的 Collection (mongoDB) 或 Redis 设置它们的存储位置
加密后的token也会有用户的类型等。(如果你不需要在后端存储token,这个就派上用场了,你可以直接解密和检查)
- 这完全取决于用例。
现在,在允许任何用户进入用户特定路由之前,请确保您首先检查令牌。
示例
app.post('/godlevelroute', godtokencheck, callrouteandfunction);
app.post('/superherolevelroute', superheroroute, callrouteandfunction);
您必须从 angular 发送令牌到 header 然后您可以从 header 中取出数据然后您可以检查该特定用户是否有权通过那条路线与否。
假设神级用户登录,然后他将拥有 godleveltoken,我们将在允许他访问该路由之前先进行检查,否则您可以只显示错误消息。
这可以是您在服务器端的示例令牌检查功能
function checkToken(req, res, next) {
var token = req.headers['accesstoken']; //access token from header
//now depending upon which system you are following you can run a check
};
节点模块建议:https://www.npmjs.com/package/jsonwebtoken
现在进入前端部分。根据您所写的内容,您正在使用 angular,您可以在显示任何页面之前拦截令牌。
您可以浏览此博客以获得我试图解释的内容的图形表示。 Click Here
我喜欢给角色起的名字-GOD, SUPER HERO & MAN,简单易懂
由于您使用的是 MEAN 堆栈,并且大部分路由验证都是在 node
上进行的,所以我更愿意保持角色 table 简单。
角色:
{
_id : 1,
name : GOD,
golbalPerms : true
},
{
_id : 2,
name : SUPER HERO,
privatePerms : true
},
{
_id : 3,
name : MAN
}
用户:
{
_id : 111,
name : Jesus,
roleId : 1
},
{
_id : 222,
name : BatMan,
roleId : 2
},
{
_id : 333,
name : Jack,
roleId : 3
}
当用户登录并将 user
对象发送回客户端时,确保将 roleId
替换为来自数据库的相应 role
对象。
即将在 Node JS 上编写代码:
通过完全了解您的用例,我们可以将它们分为以下方法 -
创建用户
CreateTodo
DeleteTodo
ReadTodo
- 更新待办事项
CommentTodo
AssignTodo
一步步来,CreateUser.
路线代码片段:
app.all('/users', users.requiresLogin);
// Users Routes
app.route('/users')
.post(users.hasPerms('globalPerms'), users.create);
在您的控制器中,您可以根据输入 globalPerms
进行验证,如果验证通过,则允许通过调用 next()
否则 return
并显示相应的错误消息来创建用户。
现在 CreateTodo && DeleteTodo :
他们两个几乎都在相同的逻辑上工作,只是有一个小技巧。
路线代码片段:
app.all('/todos', users.requiresLogin);
// Users Routes
app.route('/todos')
.post(users.hasPerms('globalPerms','privatePerms'), todos.create);
.delete(users.hasPerms('globalPerms','privatePerms'), todos.delete);
对于创建 Todo,globalPerms
与 GOD & privatePerms
与 SUPER HERO,两者其中一个是允许的。
这里的技巧将在todos.delete
方法中,只需确保user.id === todos.createById
否则SUPER HERO可能会继续删除GOD创建的Todos。
阅读待办:
创建 TODO 时,它应该存储 createById
同样,当 TODO 分配给某人时 [= =26=] 和 assignedBy
也应该被记录下来。
这使得许多其他操作变得容易处理。
user.role.globalPerms
- 给GOD所有TODO的数据。
user.role.privatePerms
- 给 TODO 的创建者 him/her 或分配给 him/her.
user.role.globalPerms === undefined && user.role.privatePerms === undefined
- 它的 MAN 和只分配给他的 TODO。
更新待办和评论待办:
这是 ReadTODO 所做的 DIY 的精确复制
最后一个,AssignTodo :
简单的一个,loggedInUser.id === todos.createdById
然后他可以分配给任何人
这里要记住两件事:
由于分配部分主要发生在你的 UI (Angular) 前面,我已经给出了检查 loggedInUser.id === todos.createdById
的方法。以任何方式登录的用户将通过读取操作看到所有 TODO,并且可以将其分配给任何 he/she 喜欢的人。
确保 SUPER HERO 只能将 TODO 分配给自己或其他 SUPER HERO 或 MAN,但不能分配给 GOD。如何在 UI 前面显示分配给选项超出了这个问题的范围。这只是一个提醒。
希望这是清楚的。
注意:没有必要在角色集合中向 MAN 授予权限,我们管理了所有可能的操作。
我目前正在学习 MEAN 堆栈,正在开发一个简单的 TODO 应用程序,并希望为此实现基于角色的访问控制 (RBAC)。我如何在 MongoDB 上设置角色和权限。
我想要3个角色(角色可能看起来很有趣,但这纯粹是为了学习):
- 上帝
- 超级英雄
- 男人
GOD - 类似于超级管理员,可以在应用程序中做任何事情。 TODO 和其他用户的 C、R、U、D 权限。可以创建一个 TODO 并将其直接分配给任何 SUPER HERO 或 MAN。随时更新或删除 TODO 或用户。
SUPER HERO - 类似于管理员,拥有对个人数据执行任何操作的超能力 - C、R、U、D 用于 TODO。无法创建任何用户。只能阅读和添加由 GOD 创建并分配给 him/her.
的 TODO 的评论MAN - 只能阅读分配给 him/her 的 TODO 并添加评论。
总结一下:
GOD - C,R,U,D [Global Level]
SUPER HERO - C,R,U,D [Private] + R,U [Assigned to him]
MAN - R,U [Assigned to him]
我知道我需要有 USERS & ROLES 集合。 ROLES 反过来应该有 PERMISSIONS 等。我如何连接它们?
可能的方法-> 在用户中嵌入角色 collection/schema: 用户文档应包含以下内容:
{
_id : "email@mail.com",
name: "lorem ipsum",
role: "MAN"
}
据您的 post 描述,只有上帝才能制定和分配 TODO。 角色集合可能包含以下内容:
{
_id : "MAN",
globalPerm: [],
privatePerm: [],
assignedPerm: ["r","u"],
},
{
_id : "SUPER_HERO",
globalPerm: [],
privatePerm: ["c","r","u","d"],
assignedPerm: ["c","r","u","d"],
},
{
_id : "GOD",
globalPerm: ["c","r","u","d"],
privatePerm: ["c","r","u","d"],
assignedPerm: ["c","r","u","d"],
}
Node JS 中间件 在为用户获得正确的权限值后,您可能想要使用中间件。 示例快速 HTTP 请求路由:
app.post('/updateTodo', permissions.check('privatePerm', 'c'), function (req, res) {
// do stuff
};
permissions.check 在实际执行函数体之前调用以更新 TODO。
因此,如果用户尝试更新待办事项,它将首先验证相应的权限。
这是一个非常广泛的问题,可以通过多种方式解决。
您已经补充说您使用的是 MEAN 堆栈,因此我的问题仅限于此。
您没有在整个问题中包括的一件事是您使用的是哪种身份验证架构。假设您正在使用基于令牌的身份验证,如今人们通常都在使用它。
我们有 3 种类型的用户。 您也可以使用不同的选项来区分令牌类型。
- 不同的 Collection (mongoDB) 或 Redis 设置它们的存储位置
加密后的token也会有用户的类型等。(如果你不需要在后端存储token,这个就派上用场了,你可以直接解密和检查)
- 这完全取决于用例。
现在,在允许任何用户进入用户特定路由之前,请确保您首先检查令牌。
示例
app.post('/godlevelroute', godtokencheck, callrouteandfunction);
app.post('/superherolevelroute', superheroroute, callrouteandfunction);
您必须从 angular 发送令牌到 header 然后您可以从 header 中取出数据然后您可以检查该特定用户是否有权通过那条路线与否。
假设神级用户登录,然后他将拥有 godleveltoken,我们将在允许他访问该路由之前先进行检查,否则您可以只显示错误消息。
这可以是您在服务器端的示例令牌检查功能
function checkToken(req, res, next) {
var token = req.headers['accesstoken']; //access token from header
//now depending upon which system you are following you can run a check
};
节点模块建议:https://www.npmjs.com/package/jsonwebtoken
现在进入前端部分。根据您所写的内容,您正在使用 angular,您可以在显示任何页面之前拦截令牌。
您可以浏览此博客以获得我试图解释的内容的图形表示。 Click Here
我喜欢给角色起的名字-GOD, SUPER HERO & MAN,简单易懂
由于您使用的是 MEAN 堆栈,并且大部分路由验证都是在 node
上进行的,所以我更愿意保持角色 table 简单。
角色:
{
_id : 1,
name : GOD,
golbalPerms : true
},
{
_id : 2,
name : SUPER HERO,
privatePerms : true
},
{
_id : 3,
name : MAN
}
用户:
{
_id : 111,
name : Jesus,
roleId : 1
},
{
_id : 222,
name : BatMan,
roleId : 2
},
{
_id : 333,
name : Jack,
roleId : 3
}
当用户登录并将 user
对象发送回客户端时,确保将 roleId
替换为来自数据库的相应 role
对象。
即将在 Node JS 上编写代码:
通过完全了解您的用例,我们可以将它们分为以下方法 -
创建用户
CreateTodo
DeleteTodo
ReadTodo
- 更新待办事项
CommentTodo
AssignTodo
一步步来,CreateUser.
路线代码片段:
app.all('/users', users.requiresLogin);
// Users Routes
app.route('/users')
.post(users.hasPerms('globalPerms'), users.create);
在您的控制器中,您可以根据输入 globalPerms
进行验证,如果验证通过,则允许通过调用 next()
否则 return
并显示相应的错误消息来创建用户。
现在 CreateTodo && DeleteTodo :
他们两个几乎都在相同的逻辑上工作,只是有一个小技巧。
路线代码片段:
app.all('/todos', users.requiresLogin);
// Users Routes
app.route('/todos')
.post(users.hasPerms('globalPerms','privatePerms'), todos.create);
.delete(users.hasPerms('globalPerms','privatePerms'), todos.delete);
对于创建 Todo,globalPerms
与 GOD & privatePerms
与 SUPER HERO,两者其中一个是允许的。
这里的技巧将在todos.delete
方法中,只需确保user.id === todos.createById
否则SUPER HERO可能会继续删除GOD创建的Todos。
阅读待办:
创建 TODO 时,它应该存储 createById
同样,当 TODO 分配给某人时 [= =26=] 和 assignedBy
也应该被记录下来。
这使得许多其他操作变得容易处理。
user.role.globalPerms
- 给GOD所有TODO的数据。
user.role.privatePerms
- 给 TODO 的创建者 him/her 或分配给 him/her.
user.role.globalPerms === undefined && user.role.privatePerms === undefined
- 它的 MAN 和只分配给他的 TODO。
更新待办和评论待办:
这是 ReadTODO 所做的 DIY 的精确复制
最后一个,AssignTodo :
简单的一个,loggedInUser.id === todos.createdById
然后他可以分配给任何人
这里要记住两件事:
由于分配部分主要发生在你的 UI (Angular) 前面,我已经给出了检查
loggedInUser.id === todos.createdById
的方法。以任何方式登录的用户将通过读取操作看到所有 TODO,并且可以将其分配给任何 he/she 喜欢的人。确保 SUPER HERO 只能将 TODO 分配给自己或其他 SUPER HERO 或 MAN,但不能分配给 GOD。如何在 UI 前面显示分配给选项超出了这个问题的范围。这只是一个提醒。
希望这是清楚的。
注意:没有必要在角色集合中向 MAN 授予权限,我们管理了所有可能的操作。