What datatype to use to store user permissions
c#
Solution
We ended up with:
public class EntityPermission
{
private readonly List<GetUserPermissionsResult> _userPermissionDataSet;
private readonly Dictionary<int, Dictionary<int, int>> _permissions;
/// <summary>
/// Constructor to generate permissions for a user
/// </summary>
/// <param name="ds">
/// Dataset of type List GetUserPermissionsResult
/// based on a stored procedure which brings back the
/// valid permissions of a user.
/// The result is a matrix of size [Enitities] * [Actions]
/// Where each entity action [index] is the value (right).
/// In general terms, the entity e with action a has right r.
/// </param>
public EntityPermission(List<GetUserPermissionsResult> ds)
{
_userPermissionDataSet = ds;
_permissions = new Dictionary<int, Dictionary<int, int>>();
SetPermissions();
}
/// <summary>
/// Called from the constructor of EntityPermission.
/// This method fills our matrix of size entity * action with
/// the valid rights.
/// </summary>
public void SetPermissions()
{
var dt = _userPermissionDataSet;
for (int i = 1; i<=Enum.GetNames(typeof(Module)).Length; i++)
{
var actionDictionary = new Dictionary<int, int>();
for (int j = 1; j<=Enum.GetNames(typeof(ActionEnum)).Length; j++)
{
var value = (from a in dt where a.EntityID == i && a.ActionID == j select a.Answer).FirstOrDefault();
if (value != null)
actionDictionary.Add(j , (int) value);
else actionDictionary.Add(j, (int)Answer.No);
}
_permissions.Add(i, actionDictionary);
}
}
/// <summary>
/// Method to get the rights provided an entity (a module)
/// and an action on that module.
/// </summary>
/// <param name="entityIdKey"></param>
/// <param name="actionIdKey"></param>
/// <returns></returns>
public int GetPermission(int entityIdKey, int actionIdKey)
{
return _permissions[entityIdKey][actionIdKey];
}
}
The readonly `List<GetUserPermissionsResult>` was a returned type from a sproc that returned a matrix based on my question - without too many details:
SELECT
e.EntityID AS EntityID,
a.ActionID AS ActionID,
CASE MAX(ar.[Rank])
WHEN 3 THEN 1 --yes
WHEN 2 THEN 3 --originator only
WHEN 1 THEN 2 --no
END AS [Answer]
FROM
....
This sproc had a bunch of joins but basically grouped by the following:
GROUP BY
e.EntityID,
a.ActionID
This ensures we get an action per a module (the entity).
We stored this object as part of the user's session:
`public EntityPermission Permission { get; set; }`
And then we simply could make a call to GetPermission to get the result:
if (((int)Answer.Yes ==
MySession.Current.Permission.GetPermission((int)Module.SubProject, (int)ActionEnum.Edit))
Problem
We've developed code that basically returns data for a user's permissions on an entity. For instance, an entity could be one of the following: ``` -Company -Contact -Project -Issue etc... ``` We then can assign policies (and a person can get multiple policies) that allow a user to perform an action: ``` -Create -Edit -Delete -Export ``` So basically one policy could say that user A has the right to create a company, but another policy which this same user has says that he does not have the right to create a company. In this case we take the rights that allow before the rights that dont allow. In this example, he/she would be allowed to create a company. So basically you end up with data like so: ``` Policy1 Company Create Yes Policy1 Company Edit Yes Policy1 Company Delete No Policy2 Company Create No Policy2 Company Edit Yes Policy2 Company Delete No ``` I have a query which we use to return what is this user's permission based on the rules we discussed. In this case running the query the result would be: ``` Company create yes Company edit yes Company delete no ``` Our app isn't just a bit yes / no for whether they can perform the action or not. We have yes / no / owner only (for records that should only be edited / deleted by the owner only. Our query is great and is returning the correct data. My question is what data type should I use in C# to basically say: Given an entity (company) given an action (create) what is the value. Basically at the end of the day I want to build a matrix that looks like this: ``` Create Edit Delete Company Yes Owner Only Yes Contact No No No Project Yes Yes Owner Only ``` The rows on the first column represent the entity, the columns after that represent the actions (create, edit, delete). The combination of the 2 for instance index: `[Company][Create] = Yes` would give you the right of the action based on the entity. So what datatype fits this model where I can perform some index like: `[Contact][Edit]=No`. We also have to session this object / come up with a way (maybe dynamically) to get the result based on an entity and action. I thought session would be good so that we can check the rights once and only once until the user logs out.