Your design seems pretty close to me. Just a couple suggestions.
users - People who will use the system. Here I have usernames and passwords.
Fine
roles - Collection of roles that users can have. Stuff like manager, admin, etc.
Fine too. But you will also need a "UserRoles" entity/table that will tell you which users have which roles. It is likely that a given user may have two or more roles.
resources - Things that users can manipulate. Like contracts, users, contract drafts, etc.
Might be just a question of semantics. I don't think users directly manipulate resources; roles do. Thus it goes user -> user role -> role -> operation -> resource
operations - Things that users can do with the resources. Like create, read, update or delete.
yep, except "roles" instead of "users"
The permissions table will look like this (one row of it): ID: 1, operation: create, resource: contract. Which means a permission to create a contract.
Hmmm. There are two ways to go with this. You could have the permissions table you describe, but you would also need an additional RolePermissions
table/entity that tells you which role has which permission. But I am not sure that is necessary.
A simpler way to do it is a permissions table/entity with these columns/attributes: Role ID, Operation ID, ResourceID. That way, operations x resource combinations are assigned directly to a role, rather than loaded into a permission that is assigned to a role. It eliminates one entity. There really isn't need for a separate role-agnostic permissions table, unless you wish to predefine what permissions combinations are allowed and which ones are not.
It's sometimes difficult to distinguish between real access control rules and domain invariants borderlining on access control.
Especially, rules that depend on data only available far into the course of a particular piece of domain logic might not easily be extractible out of the domain. Usually, Access Control is called before or after a domain operation is performed but not during.
Vaughn Vernon's assert (forum.IsModeratedBy(moderator))
example probably should have been outside the Domain, but it is not always feasible.
I would need to pass not just the userId, but the identifier of the
protected resource (the id of the post, forum, etc.) to the security
context, which probably should not care about these things (is it
correct?)
If there's a Security BC and you want it to handle that logic, it doesn't have to know what a Forum is in detail but :
- It could just have knowledge of concepts like "moderated by" and grant or deny access rights accordingly.
- You could have adapter logic that subscribes to Core Domain events and translates them to simple (resource, authorizedUsers) key value pairs for the Security BC to store and use.
Best Answer
Item level permissions will require both database modelling and application enforcement.
Essentially, You'll want to create an "item security" table that relates the RowIDs and PermissionIDs to each other. The application will then have to determine if the current user has the right permissions to view the item that they requested. The database can also leverage stored procedures to filter the rows returned for a particular table based on the permissions.
This kind of system can easily get complex very quickly. Make sure you plan ahead and do plenty of modelling and use-case testing of the model before moving forward.
Also, if SharePoint is a good fit for this application, you may consider just using SharePoint instead of reinventing the wheel.
EDIT: I had some free time, so I modeled up a schema that I've used in the past for this type of scenario:
You would want to check the user's permissions against the item they request on your site in your application code. If the user's permissions don't match, they don't have access. You may also want to implement some form of "admin" access where if a user has the "admin" permission they can access all items.
You can pass the user's ID in any stored procedures you use to check their permissions and to filter list results to only the items they have permission to access.