使用什么数据类型来存储用户权限

本文关键字:存储 用户 权限 数据类型 什么 | 更新日期: 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]

到目前为止,这给了我们一个空矩阵。我们必须记住,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
这就是我想要的,因为我想写类似于这样的代码(记住这只是伪):
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))