使用二进制与或非 的方式进行权限分配
Posted 第十一次进球
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用二进制与或非 的方式进行权限分配相关的知识,希望对你有一定的参考价值。
我们一般的思路设计一个权限系统是这样的:
假设有个游戏如果同时大拇指点击,中指点击,小指点击就会暴击
权限表(T_Right),字段(C_RightId,C_RightName)
用户权限分配表(T_UserRights),字段(C_UserId,C_RightId)
测试数据如下:
1 /****** Object: Table [dbo].[T_Right] Script Date: 2016/6/4 10:43:18 ******/ 2 SET ANSI_NULLS ON 3 GO 4 SET QUOTED_IDENTIFIER ON 5 GO 6 SET ANSI_PADDING ON 7 GO 8 CREATE TABLE [dbo].[T_Right]( 9 [C_RightId] [int] NOT NULL, 10 [C_RightName] [varchar](50) NOT NULL, 11 CONSTRAINT [PK_T_Right] PRIMARY KEY CLUSTERED 12 ( 13 [C_RightId] ASC 14 )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 15 ) ON [PRIMARY] 16 17 GO 18 SET ANSI_PADDING OFF 19 GO 20 /****** Object: Table [dbo].[T_UserRights] Script Date: 2016/6/4 10:43:18 ******/ 21 SET ANSI_NULLS ON 22 GO 23 SET QUOTED_IDENTIFIER ON 24 GO 25 CREATE TABLE [dbo].[T_UserRights]( 26 [C_UserId] [int] NOT NULL, 27 [C_RightId] [int] NOT NULL, 28 CONSTRAINT [PK_T_UserRights] PRIMARY KEY CLUSTERED 29 ( 30 [C_UserId] ASC, 31 [C_RightId] ASC 32 )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 33 ) ON [PRIMARY] 34 35 GO 36 INSERT [dbo].[T_Right] ([C_RightId], [C_RightName]) VALUES (1, N\'大拇指点击\') 37 GO 38 INSERT [dbo].[T_Right] ([C_RightId], [C_RightName]) VALUES (2, N\'食指点击\') 39 GO 40 INSERT [dbo].[T_Right] ([C_RightId], [C_RightName]) VALUES (3, N\'中指点击\') 41 GO 42 INSERT [dbo].[T_Right] ([C_RightId], [C_RightName]) VALUES (4, N\'无名指点击\') 43 GO 44 INSERT [dbo].[T_Right] ([C_RightId], [C_RightName]) VALUES (5, N\'小指点击\') 45 GO 46 INSERT [dbo].[T_UserRights] ([C_UserId], [C_RightId]) VALUES (1, 1) 47 GO 48 INSERT [dbo].[T_UserRights] ([C_UserId], [C_RightId]) VALUES (1, 2) 49 GO 50 INSERT [dbo].[T_UserRights] ([C_UserId], [C_RightId]) VALUES (1, 3) 51 GO 52 INSERT [dbo].[T_UserRights] ([C_UserId], [C_RightId]) VALUES (1, 4) 53 GO 54 INSERT [dbo].[T_UserRights] ([C_UserId], [C_RightId]) VALUES (1, 5) 55 GO
于是,我们得到一个人所拥有的权限就是一个集合为 (类型为:List<int>)userRights:
select * from [dbo].[T_UserRights] where C_UserId=1
C_UserId C_RightId ----------- ----------- 1 1 1 2 1 3 1 4 1 5 (5 行受影响)
我们要判判断用户是否有 暴击权限的时候,可能会这样判断:
1 List<int> userRights = DataBase.GetUserRightsById(1); 2 List<int> bjRights = DataBase.GetBJRights(); 3 bool hasbjrights = true; 4 foreach(var right in bjRights) 5 { 6 if (userRights.Contains(right)) 7 { 8 hasbjrights = false; 9 break; 10 } 11 } 12 if (hasbjrights) 13 { 14 //有权限 15 } 16 else 17 { 18 //无权限 19 }
此方法的特点是判断是否同时拥有 暴击 权限就需要两层循环判断(应该也有其他方法)。
当然另外一个思路是(用户权限分配表(T_UserRights),字段(C_UserId,C_RightId)),C_RightId为字符串类型,
权限存储形式为: 1 1,3,5 一个用户的权限用一个字符串存储就行了) 当然也是需要两层循环判断。
下面说下我的方法:
数据库设计如下:
1 /****** Object: Table [dbo].[T_Right] Script Date: 2016/6/4 11:29:57 ******/ 2 SET ANSI_NULLS ON 3 GO 4 SET QUOTED_IDENTIFIER ON 5 GO 6 SET ANSI_PADDING ON 7 GO 8 CREATE TABLE [dbo].[T_Right]( 9 [C_RightId] [int] NOT NULL, 10 [C_RightName] [varchar](50) NOT NULL, 11 CONSTRAINT [PK_T_Right] PRIMARY KEY CLUSTERED 12 ( 13 [C_RightId] ASC 14 )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 15 ) ON [PRIMARY] 16 17 GO 18 SET ANSI_PADDING OFF 19 GO 20 /****** Object: Table [dbo].[T_UserRights] Script Date: 2016/6/4 11:29:57 ******/ 21 SET ANSI_NULLS ON 22 GO 23 SET QUOTED_IDENTIFIER ON 24 GO 25 CREATE TABLE [dbo].[T_UserRights]( 26 [C_UserId] [int] NOT NULL, 27 [C_Rights] [int] NOT NULL, 28 CONSTRAINT [PK_T_UserRights_1] PRIMARY KEY CLUSTERED 29 ( 30 [C_UserId] ASC 31 )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 32 ) ON [PRIMARY] 33 34 GO 35 INSERT [dbo].[T_Right] ([C_RightId], [C_RightName]) VALUES (1, N\'大拇指点击\') 36 GO 37 INSERT [dbo].[T_Right] ([C_RightId], [C_RightName]) VALUES (2, N\'食指点击\') 38 GO 39 INSERT [dbo].[T_Right] ([C_RightId], [C_RightName]) VALUES (4, N\'中指点击\') 40 GO 41 INSERT [dbo].[T_Right] ([C_RightId], [C_RightName]) VALUES (8, N\'无名指点击\') 42 GO 43 INSERT [dbo].[T_Right] ([C_RightId], [C_RightName]) VALUES (16, N\'小指点击\') 44 GO 45 INSERT [dbo].[T_UserRights] ([C_UserId], [C_Rights]) VALUES (1, 31) 46 GO
我们得到一个人所拥有的权限就是一个对象为 userRight(UserId,Rights):
select * from [dbo].[T_UserRights] where C_UserId=1
C_UserId C_Rights ----------- ----------- 1 31 (1 行受影响)
这个设计跟上面的设计都表示UserId为1的用户拥有所有的权限
原因是:将权限拆为二进制表示:
C_RightId C_RightName ----------- -------------------------------------------------- 00001 大拇指点击 00010 食指点击 00100 中指点击 01000 无名指点击 10000 小指点击 (5 行受影响)
所有权限或的结果就是11111,就是31
我们要判判断用户是否有 暴击权限的时候,代码如下:
1 int Rights = DataBase.GetUserRightById(1); 2 int bjRight = DataBase.GetBJRight(); 3 if ((Rights & bjRight) == Rights) 4 { 5 //有权限 6 } 7 else 8 { 9 //无权限 10 }
这样做,在进行逻辑处理的时候只要进行与或即可。方便,效率也高。
缺点也是有的,就是最大的权限的值会以2的指数增长,那么权限多的时候这个值有无可能装不下
灵感来源:System.Windows.Forms.Control.Anchor,对于winform熟悉的朋友应该知道这个属性吧:
获取或设置控件绑定到的容器的边缘并确定控件如何随其父级一起调整大小。
1 // 2 // 摘要: 3 // 指定控件如何锚定到其容器的边缘。 4 [Flags] 5 public enum AnchorStyles 6 { 7 // 8 // 摘要: 9 // 该控件未锚定到其容器的任何边缘。 10 None = 0, 11 // 12 // 摘要: 13 // 该控件锚定到其容器的上边缘。 14 Top = 1, 15 // 16 // 摘要: 17 // 该控件锚定到其容器的下边缘。 18 Bottom = 2, 19 // 20 // 摘要: 21 // 该控件锚定到其容器的左边缘。 22 Left = 4, 23 // 24 // 摘要: 25 // 该控件锚定到其容器的右边缘。 26 Right = 8 27 }
表示控件同时根据父控件的上,左,右进行调整大小 代码如下:
this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right)));
文笔不好,勿喷。
以上是关于使用二进制与或非 的方式进行权限分配的主要内容,如果未能解决你的问题,请参考以下文章
数字逻辑电路 逻辑运算 与或非与非或非与或非异或同或 二进制运算技巧