Am currently learning MEAN stack, developing a simple TODO's app and want to implement Role Based Access Control (RBAC) for that. How do i set up roles & permission on MongoDB.
I want 3 roles (roles may look funny but this is purely to learn) :
GOD - similar to super admin, can do anything in the application. C,R,U,D permissions for TODO's and for other users too. Can Create a TODO & assign it to any SUPER HERO or MAN directly. Update or Delete either a TODO or a User at any point in time.
SUPER HERO - similar to admin, has super power to do anything on his personal Data - C,R,U,D for TODO's. Can't create any users. Can only Read & add comments for TODO's created by GOD & assigned to him/her.
MAN - Can only Read and add comments to TODO's assigned to him/her.
To sum it up :
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]
I understand that i need to have USERS & ROLES collections. Where ROLES inturn should have PERMISSIONS etc. How do i wire them all ?
I like names given to roles - GOD, SUPER HERO & MAN , easy to understand.
As you are using MEAN stack and much of routes validation happens on node
, i would prefer keeping roles table simple.
Roles :
{
_id : 1,
name : GOD,
golbalPerms : true
},
{
_id : 2,
name : SUPER HERO,
privatePerms : true
},
{
_id : 3,
name : MAN
}
Users :
{
_id : 111,
name : Jesus,
roleId : 1
},
{
_id : 222,
name : BatMan,
roleId : 2
},
{
_id : 333,
name : Jack,
roleId : 3
}
When user logs in and sending user
object back to client, make sure to replace roleId
with corresponding role
object from DB.
Coming to code on Node JS :
By completely understanding your usecase we can divide them into following methods -
CreateUser
CreateTodo
DeleteTodo
ReadTodo
CommentTodo
AssignTodo
Lets go step by step, CreateUser .
Routes code snippet :
app.all('/users', users.requiresLogin);
// Users Routes
app.route('/users')
.post(users.hasPerms('globalPerms'), users.create);
In your Controller you can validate based on the input globalPerms
, if validated allow to create user by calling next()
else return
with corresponding error message.
Now CreateTodo && DeleteTodo :
Both of them pretty much work on same logic with a small trick.
Routes code snippet :
app.all('/todos', users.requiresLogin);
// Users Routes
app.route('/todos')
.post(users.hasPerms('globalPerms','privatePerms'), todos.create);
.delete(users.hasPerms('globalPerms','privatePerms'), todos.delete);
For creating a Todo, globalPerms
are with GOD & privatePerms
are with SUPER HERO , both of them can be allowed.
Trick here will be in todos.delete
method, just ensure user.id === todos.createById
else SUPER HERO may go on to delete Todos created by GOD.
ReadTodo :
When a TODO is created it should have a createById
stored likewise when a TODO is assigned to someone then assignedTo
and assignedBy
should be recorded too.
This makes lot of other operations easy to handle.
user.role.globalPerms
- give GOD all TODO's data.
user.role.privatePerms
- give TODO's either createdBy him/her or assigned to him/her.
user.role.globalPerms === undefined && user.role.privatePerms === undefined
- its MAN and give TODO's which are only assignedTo him.
UpdateTodo & CommentTodo :
This is exact replica of what ReadTODO does so DIY
Last one, AssignTodo :
Simple one, loggedInUser.id === todos.createdById
then he can assign it to anyone.
Two things to keep in mind here :
As assigning part mostly happens on your UI (Angular) front, i have given that approach of checking loggedInUser.id === todos.createdById
. Logged in user any ways will see all TODO's by read operation and can assign it to anyone he/she likes.
Make sure a SUPER HERO can only assign a TODO to himself or other SUPER HERO or to a MAN but not to GOD. How you show Assign to options on UI front is out of scope of this question. This is just a heads up.
Hope this was clear.
NOTE : There was no necessity to give permissions to MAN in Roles collection & we managed all possible operations with out that.
This is a very broad question which can be solved in many ways.
You have added that you are using MEAN stack therefore I'll restrict my question to that.
One thing that you haven't included in the whole question is what kind of authentication architecture are you using. Let's say you are using token based authentication, generally people these days use it.
We have 3 types of users. You have different options available to differentiate between type of tokens as well.
The encrypted token will have type of the user as well etc.. (This will come in handy if you don't need to store tokens on the backend, you can just decrypt and check)
Now, before allowing any user's entry to user specific route make sure that you are checking the token first.
Example
app.post('/godlevelroute', godtokencheck, callrouteandfunction);
app.post('/superherolevelroute', superheroroute, callrouteandfunction);
You must send token in header from angular and then you can take the data out from the header and then you can check if that specific user has permission to go through that route or not.
Let's say a god level user is logged in then he'll have the godleveltoken with him and we'll check that first before allowing him to access that route or else you can just show error message.
This can be your sample token checking function on server end
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
};
Node Module Suggestion : https://www.npmjs.com/package/jsonwebtoken
Now coming to frontend part. You are using angular based on what you have written, you can intercept the token before showing any page.
You can go through this blog to get a pictorial representation of what I have tried to explain. Click Here
Possible approach-> have role embedded in user collection/schema: users document shall have the following:
{
_id : "email@mail.com",
name: "lorem ipsum",
role: "MAN"
}
As far as your post describes, only god can make and assign TODOs. Roles Collection may hold the following:
{
_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 Middlewares After getting correct permission values for a user, you might want to use middlewares. Sample express HTTP request route:
app.post('/updateTodo', permissions.check('privatePerm', 'c'), function (req, res) {
// do stuff
};
permissions.check is called before actually executing function body to update TODO.
Hence if a user tries to update a todo, it will first verify the corresponding permissions.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.