我们开发的代码基本上返回了用户对实体的权限的数据。 例如,实体可以是以下之一:
-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(对于只能由所有者编辑/删除的记录。我们的查询非常好并且返回正确的数据。
我的问题是我应该在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
。
我们还必须会话这个对象/提出一种方法(可能是动态的)来获得基于实体和动作的结果。
我认为会话会很好,所以我们可以只检查一次权限,直到用户退出为止。
答案 0 :(得分:4)
这不是最后的答案,但我想到了这一点,也许我可以得到一些反馈。以下是我提出的建议:
我在考虑如何存储权限,我相信我已经想出了一些可能有用的东西。
我一直在想这一切 - 我需要的只是一个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]
到目前为止,这给了我们矩阵作为空矩阵。我们必须记住C#中的数组/矩阵是基于零的...这很好。我们已经有一个存储过程,它返回如下数据:
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
这将是每个用户...这正是我想要的,因为我想编写与此类似的代码(记住这只是pseduo):
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,因为数组是基于零的...我们不需要任何其他东西。它可能不是最好的解决方案,但我认为它可以工作......
答案 1 :(得分:3)
我们最终得到了:
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];
}
}
readonly 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
....
这个sproc有一堆连接,但基本上按以下方式分组:
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))