What you want is a capability list approach.
The solution to this is a mapping of roles to capabilities, similar to this:
>Online Anon User Admin
Article ReadOnly ReadWrite ReadWrite
Article.List ReadOnly ReadOnly ReadOnly
Article.Edit Hidden ReadWrite ReadWrite
Article.Delete Hidden ReadOnly ReadWrite
Article.Title.Edit * * ReadWrite
In practice, these will be your coordinates:
>(system state)
The system may be "Online, Offline, Maintenance" and maybe more.
Use the initial >
to find the start of your matrix in the file (you'll have many of these). In C# you'll have an enum
.
On the same line are the roles:
Anon User Admin
Then on the left side you'll have the capabilities scoped into namespaces and actions:
<item>
<item>.<action>
<item>.<field>.<action>
<item>.<field>.<value>.<action>
The cells will contain one of these values:
Hidden, ReadOnly, ReadWrite or *
The *
will mean "inherit" from the parent item or field.
This way you'll be able to fine-tune the permissions based on items, actions, roles and the current system state.
A simple parser translating the list into an in-memory structure will do. Don't put this on a DB, it will be a pain. Keeping it on the text-file/in-memory level is better. Add a FileSystemWatcher
to read that file whenever it is changed for additional functionality and leverage lazy loading. Also, store it in Application state
memory, not in a session.
Remember: the default will be Hidden
(not even read access, the item/action will be completely inaccessible to that role.
Your real concern will then be which roles you'll really need (in my experience a role pretty much maps to an UML actor, maybe with some slight variances), and what the items/fields/values and actions really are. When you write an item you can really mean a group of items. There is no need to map the capability list directly unto a database/entity or code structure. The capability list is on a higher language level, it is semantic and bound to the domain, not to the code (I want to stress this because it's the real power behind this approach).
Once you have implemented this approach with a simple parser and helper object (Information Expert Principle is well advised, avoid Singletons) you'll be able to reuse it in many applications.