MongoDB + Node JS +基于角色的访问控制(RBAC)

时间:2016-09-28 11:53:55

标签: javascript node.js mongodb rbac

我正在学习MEAN 堆栈,开发一个简单的TODO应用程序,并希望为此实现基于角色的访问控制(RBAC)。我如何设置角色& MongoDB的许可。

我想要3个角色(角色可能看起来很有趣,但这纯粹是为了学习):

  • 上帝
  • SUPER HERO
  • MAN

GOD - 与超级管理员类似,可以在应用程序中执行任何操作。 TODO的C,R,U,D权限以及其他用户的权限。可以创建一个TODO&直接分配给任何SUPER HERO或MAN。在任何时间点更新或删除TODO或用户。

SUPER HERO - 与管理员类似,拥有超强的权力可以为他的个人数据做任何事 - C,R,U,D为TODO' s。无法创建任何用户。只能阅读&为GOD& amp;创建的TODO添加评论分配给他/她。

MAN - 只能阅读并添加评论给分配给他/她的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等。如何将它们全部连接起来?

3 个答案:

答案 0 :(得分:16)

我喜欢角色的名字 - GOD,SUPER HERO&男人,易于理解。

当您使用MEAN堆栈并且node上发生了大量路由验证时,我更希望保持角色表简单。

角色:

{
_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替换为来自DB的相应role对象。

来自Node JS的代码:

通过完全理解您的用例,我们可以将它们分为以下几种方法 -

  • CREATEUSER

  • CreateTodo

  • DeleteTodo

  • ReadTodo

  • UpdateTodo
  • 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。

ReadTodo

当创建 TODO 时,如果 TODO 分配给某人createById和{{1},则同样应存储assignedTo也应该记录下来。

这使得许多其他操作变得容易处理。

assignedBy - 向上帝提供所有TODO的数据。

user.role.globalPerms - 将TODO创建给他/她或分配给他/她。

user.role.privatePerms - 它的MAN并且只给TODO,而这些TODO只被分配给他。

UpdateTodo& CommentTodo

这是ReadTODO所做的精确复制DIY

最后一个, AssignTodo

简单的一个,user.role.globalPerms === undefined && user.role.privatePerms === undefined然后他可以将它分配给任何人。

这里要记住两件事:

  1. 由于分配部分主要发生在你的UI(Angular)前面,我已经给出了检查loggedInUser.id === todos.createdById的方法。以任何方式登录用户都会通过阅读操作查看所有TODO,并可以将其分配给他/她喜欢的任何人。

  2. 确保 SUPER HERO 只能将TODO分配给自己或其他SUPER HERO或MAN,但不能分配给GOD。如何在UI前面显示分配给选项超出了此问题的范围。这只是一个提醒。

  3. 希望这很清楚。

    注意:没有必要在角色集合中为MAN提供权限。我们完成了所有可能的操作。

答案 1 :(得分:1)

这是一个非常广泛的问题,可以通过多种方式解决。

你已经添加了你正在使用MEAN堆栈,因此我将我的问题限制在那里。

您未在整个问题中包含的一件事是您使用的是哪种身份验证体系结构。假设您正在使用基于令牌的身份验证,通常人们现在使用它。

我们有3种类型的用户。 您可以使用不同的选项来区分令牌类型。

  1. 不同的集合(mongoDB)或Redis设置它们存储的位置
  2. 加密令牌也会有用户类型等。(如果您不需要在后端存储令牌,这将派上用场,您可以解密并检查)

    • 完全取决于用例。
  3. 现在,在允许任何用户进入用户特定路线之前,请确保首先检查令牌。

    示例

    app.post('/godlevelroute', godtokencheck, callrouteandfunction);
    app.post('/superherolevelroute', superheroroute, callrouteandfunction);
    

    您必须从angular发送标头,然后您可以从标头中取出数据,然后您可以检查该特定用户是否有权通过该路由。

    让我们说一个神级用户登录然后他会和他一起进行神奇的说法,我们会在允许他访问该路线之前先检查一下,否则你只能显示错误信息。

    这可以是服务器端的样本令牌检查功能

    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

    现在来到前端部分。您根据所写的内容使用角度,您可以在显示任何页面之前拦截令牌。

    您可以浏览此博客,以获得我试图解释的图片。 Click Here

答案 2 :(得分:0)

可能的方法 - >具有嵌入用户集合/架构中的角色: 用户文档应具有以下内容:

{
    _id : "email@mail.com",
    name: "lorem ipsum",
    role: "MAN"
}

就你的帖子所描述的,只有上帝可以制作和分配TODO。 Roles Collection可能包含以下内容:

{
    _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"],
}

节点JS中间件 获取用户的正确权限值后,您可能希望使用中间件。 示例表达HTTP请求路由:

app.post('/updateTodo', permissions.check('privatePerm', 'c'), function (req, res) {
 // do stuff

};

在实际执行函数体以更新TODO之前调用permissions.check。

因此,如果用户尝试更新待办事项,它将首先验证相应的权限。