I have a similar situation in my application, which can be extended via plugins and the plugins can bring in their own permission. I solved that the following way:
- static/common
PermissionManager
- very module/form/plugin can register its available permissions in the manager
- the "permission manager UI" lists all available permissions and lets the admin assign them to users
- on access every module/form/plugin asks the manager if the current user has the permission
Simplified class structure:
public class PermissionManager
{
public static Dictionary<string, IEnumerable<string>> AvailablePermissions { get; set; }
public static bool? Can(User user, string permission)
{
// check DB
return DENIED ? false : (ALLOWED ? true : null);
}
}
public class MyPlugin : IPlugin
{
public void Init()
{
PermissionManager.AvailablePermissions["MyPlugin"] =
new List<string>() { "Permission1", "Permission2" };
}
public void DoWork()
{
if (PermissionManager.Can(user, "Permission1") != true)
throw new NotAllowedException();
// do work
}
}
This is the basic patter I use. Of course you should use constants or similar for the permission names/keys. The admin UI can then iterate AvailablePermissions
in the configuration UI.
In the DB I have something like the following (EF Code-First):
public class UserProfilePermissions
{
public UserProfile User { get; set; }
public Permission Permission { get; set; }
public bool IsAllowed { get; set; }
}
public class Permission
{
public int Id { get; set; }
public string Key { get; set; }
public string Group { get; set; }
}
So for every permission there is one Permission
entry created (on the first assignment) in the DB and mapped via the mapping table using the IsAllowed
to define "ALLOWED" or "DENIED".
The null
value defines a not set permission so default values can be used (=> not set permission does not always say "DENIED").
The mapping table can also be used in the same style for e.g. roles.