使用什么数据类型来存储用户权限
本文关键字:存储 用户 权限 数据类型 什么 | 更新日期: 2023-09-27 18:12:25
我们开发的代码基本上返回用户对实体的权限的数据。例如,一个实体可以是以下内容之一:
-Company
-Contact
-Project
-Issue etc...
然后我们可以分配策略(一个人可以获得多个策略),允许用户执行操作:
-Create
-Edit
-Delete
-Export
所以基本上一个策略可以说用户A有权创建公司,但同一用户拥有的另一个策略说他没有创建公司的权利。在这种情况下,我们把允许的权利放在不允许的权利之前。在这个例子中,他/她将被允许创建一个公司。
最后得到的数据是这样的:
Policy1 Company Create Yes
Policy1 Company Edit Yes
Policy1 Company Delete No
Policy2 Company Create No
Policy2 Company Edit Yes
Policy2 Company Delete No
我有一个查询,根据我们讨论的规则,我们使用它来返回这个用户的权限。
在这种情况下,运行查询的结果将是:
Company create yes
Company edit yes
Company delete no
我们的应用程序不只是一点是/否,他们是否可以执行操作。我们有yes/no/owner only(对于只应该由所有者编辑/删除的记录)。我们的查询很好,正在返回正确的数据。
我的问题是我应该在c#中使用什么数据类型来基本上说:
给定一个实体(公司)给定一个动作(创建)值是什么?基本上在一天结束的时候,我想建立一个像这样的矩阵:
Create Edit Delete
Company Yes Owner Only Yes
Contact No No No
Project Yes Yes Owner Only
第一列上的行表示实体,之后的列表示操作(创建、编辑、删除)。2的组合例如索引:[Company][Create] = Yes
将赋予你基于实体的行动权。
那么什么数据类型适合这个模型,我可以执行一些索引:[Contact][Edit]=No
。我们还必须会话这个对象/想出一种方法(可能是动态的)来获得基于实体和动作的结果。
我认为会话应该是好的,这样我们可以检查一次权限,只有一次,直到用户注销。
这不是一个最终的答案,但我想过这个,也许我可以得到一些反馈。下面是我想到的:
我正在考虑如何存储权限,我相信我已经想到了一些可能可行的方法。
我一直在想——我所需要的只是一个2d矩阵……然后显而易见的是,为什么我们不使用一个简单的2d int矩阵?这是可行的,至少在纸上是可行的。
如你所知,我们有一些枚举:
Modules Answer Action
Contact = 1 Yes = 1 Create = 1
Corp = 2 No = 2 Edit = 2
Company = 3 Originator Only = 3 Delete = 3
Program = 4 View = 4
Project = 5 List =5
SubProject = 6 Export = 6
Issue = 7
LL = 8
User = 9
在这种情况下,我们有9个模块和6种动作类型,因此我们需要一个大小为[9x6]的矩阵来基于矩阵[i,j]生成54个可能的条目。即使我们添加了更多的模块和更多的操作,这也可以工作。
类型简单:int[,] permissions = new int[Enum.GetNames(typeof(Modules)).Length, Enum.GetNames(typeof(Action)).Length];
翻译过来就是:int[,] permissions = new int[9,6]
Module Action Answer
1 (Contact) 1 (Create) 1 (Yes)
1 (Contact) 2 (Edit) 1 (Yes)
1 (Contact) 3 (Delete) 2 (No)
…..
2 (Corp) 1 (Create) 1 (Yes)
2 (Corp) 2 (Edit) 1 (Yes)
Etc…etc…
现在我们用下面的代码来填充数组,这只是c#伪代码:
for(int i=0; i<Enum.GetNames(typeof(Modules)).Length; i++) {
Reader.read(); //read the first row from the database
For(int j=0; j<Enum.GetNames(typeof(Action)).Length; j++) {
Permissions[i,j] = reader[“Answer”]; //assign the answer from the returned row to the array
If( j<Enum.GetNames(typeof(Action)).Length-1) {
Reader.read(); //read next row in database
} //end if condition
} //end for j
} //end for i
这个循环将产生如下结果:
1 Create 2 Edit 3 Delete 4 View 5 List 6 Export
1(Contact) 1 1 2 1 1 1
2(Corp) 1 3 2 1 1 1
3(Company) 1 1 1 1 1 1
4(Program) 1 1 1 1 1 1
5(Project) 1 1 2 1 1 1
6(SubProject) 1 1 2 1 1 1
7(Issues) 1 1 1 2 1 1
8(LL) 1 1 1 1 1 1
9(User) 2 2 2 1 2 2
这就是我想要的,因为我想写类似于这样的代码(记住这只是伪):
If(MySession.Current.Permission[(int)Module.Contact – 1, (int)Action.Create] == (int)Answer.Yes)
{
//this allows contact create
}
这是非常灵活的,因为我们可以潜在地添加任何新模块而不影响任何东西。我可以通过Permission[Module.ModuleIWant – 1, Action.ActionIWant – 1]
简单地引用事物。
我们只是确保从它拿走1,因为数组是从零开始的,我们不需要其他任何东西。这可能不是最好的解决方案,但我认为它可以工作。
最后:
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];
}
}
只读的List<GetUserPermissionsResult>
是从一个基于我的问题返回矩阵的sproc返回的类型-没有太多的细节:
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
....
这个进程有一堆连接,但基本上按以下方式分组:
GROUP BY
e.EntityID,
a.ActionID
这样可以确保每个模块(实体)都有一个动作。
我们将这个对象存储为用户会话的一部分:
public EntityPermission Permission { get; set; }
然后我们可以简单地调用GetPermission来获得结果:
if (((int)Answer.Yes ==
MySession.Current.Permission.GetPermission((int)Module.SubProject, (int)ActionEnum.Edit))