ACL best practices, store roles in user object, or separate table/collection?
Asked Answered
J

2

9

I am using nodejs, and have been researching acl/authorization for the past week. I have found only a couple, but none seem to have all the features I require. The closest has been https://github.com/OptimalBits/node_acl, but I don't think it supports protecting resources by id (for example, if I wanted to allow user 12345 and only user 12345 to access user/12345/edit). Hence, I think I will have to make a custom acl solution for myself.

My question regarding this is, what are some pros and cons to storing roles (user, admin, moderator, etc.) under each user object, as opposed to creating another collection/table that maps each user with their authorization rules? node_acl uses a separate collection, whereas most of the other ones depend on the roles array in user objects.

By the way, I am using Mongodb at the moment. However I have not researched the pros and cons yet of using relational vs. nonrelational databases for authentication yet, so if let me know if your answer depends on that.

As I was typing this up, I thought of one thing. If I store roles in a separate collection, it is more portable. I would be able to swap out the acl system much more easily. (I think?)

Jilolo answered 12/1, 2013 at 17:38 Comment(0)
G
10

The question here seems like it could be abstracted from "where should I store my roles" to "how should I store related information in Mongo (or NoSQL in general)". It's a relation vs non-relational modeling issue.

Non-Relational

Using Node + Mongo, storing the roles on the user will make it really easy to determine if a user has access to the feature, given that you can just look in the 'roles' property. The trade off is that you have lots of duplicate information ('user_read' could be a role on every user account) and if you end up changing that property, you'll need to update it inside every user object.

You could store the roles in their own collection and then store the id for that entry in the Roles collection on your User model, but then you'll still need to fetch the actual record from the collection to display any of it's information (though arguably this could be a rare occurrence)

Relational

Storing these in a relational DB would be a more "traditional" approach in that you can establish the relationships between the tables (via FKs / join tables or what not). This can be a good solution, but then you no longer have the benefits of using a NoSQL database.

Summary

If the rest of your app is stored in Mongo and has to stay there (for performance or whatever constraint) then you are probably better off doing it all in Mongo. Most of the advice I've come across says don't mix & match data stores, e.g. use one or the other, but not both. That being said, I've done projects with both and it can get messy but sometimes the pros outweigh the cons.

Geoffreygeoffry answered 12/1, 2013 at 18:3 Comment(8)
I'm dying to know the rest of the summary! :)Jilolo
Haha thanks. Must have lost focus and not realized. I tend to trail off like that when I speak too ;)Geoffreygeoffry
@DavidWelch, in general what you say makes sense, but there are times that relational "style" makes sense in the context of NoSQL. For example, what if I am in Mongo (or Couch or whatever), and I have these big user objects that are updated infrequently, but roles are updated frequently. Even in NoSQL, wouldn't it make sense to have a separate collection for the roles, so you can access them atomically, without constantly updating the user?Soutache
@Soutache better late than never on a response, right? ;) You definitely have a good point and there's an argument to be made there. However, most NoSQL solutions I've used have very performant write operations so issuing a write to the roles isn't expensive (assuming you already know which doc to update)Geoffreygeoffry
Hi @DavidWelch, sure! Interesting, what you say shows my assumptions about how writes occur. Perhaps I need to question my assumptions.Soutache
Hi @DavidWelch , keeping ACL logic with db and checking for permission for each call isn't it overhead to server ? it will create extra payload first to check permissions and there after to fetch data. i was thinking to use Node ACL this with memory based. can you suggest something optimised way to overcome this situation ?Proteus
@SumeetGohil Yes, a read on each request would be taxing, especially if stateless. However, introducing a caching layer in front of your datasource (like Redis) can quickly alleviate this problem. At least, that's what we've done and seen good results withGeoffreygeoffry
@DavidWelch can you provide some good resources/examples where i can learn more about RedisProteus
C
3

I like @DavidWelch answer, but I'd like to tackle the question from another perspective because the library mentioned gives the option to use a different data store entirely.

Storing roles in a separate data store:

  • (Pro) Can make the system more performant if you are using a faster data store. (More advantageous in distributed environments?)
  • (Con) You will have to ensure consistency between the two data stores.

General notes:

  • You can add roles/permissions such as 'blog\123' in acl. You can also give a user permissions based on verbs such as put, delete, get, etc..
  • I think it is easier to create a pluggable solution that does not depend on your storage implementation. Perhaps that is why acl does not store roles in the same collections you have.
  • If you choose to keep the roles in your own collection, consider adding them to a token (JWT). That way, you will not have to check your collection for every request that needs authorization.

I hope that helped.

Caber answered 3/5, 2016 at 2:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.