用于存储用户权限的数据类型

时间:2014-07-09 21:19:23

标签: c#

我们开发的代码基本上返回了用户对实体的权限的数据。 例如,实体可以是以下之一:

-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。 我们还必须会话这个对象/提出一种方法(可能是动态的)来获得基于实体和动作的结果。

我认为会话会很好,所以我们可以只检查一次权限,直到用户退出为止。

2 个答案:

答案 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))