权限的存储与验证
大部分应用程序都会涉及到用户权限而用什么方式来存储和对所需权限进行验证则是个常常会遇到的问题。
常用的方法有以下几种:
第一种方法:
将每个权限编号如 10001,10002,10003......等,程序上可能创建一个枚举或多个常量来对应这些编号,数据库结构上用nchar字段,将用户所拥有的权限编号拼接起来存储在这个字段里。实体类中也只需要一个string字段来存储,验证权限时只需调用权限字段的IndexOf函数就可以判断是否含有特定编号的权限。
优点:
1.存储结构简单只需要一个字段就可以解决。
2.验证权限也很容易。
缺点:
1.权限多的时候字段长度就需要设置得很大。
2.没办法一次验证多个权限。
3.插入和删除权限比较复杂。
第二种方法:
以一个用户权限表来存储用户所拥有的权限。
如:
UserPower:用户权限表
Id |
标示列 |
PowerId | 权限Id |
UserId | 用户Id |
程序上可以用一个枚举来对应权限Id,实体类可以使用数组或集合来存储,数组的话需要遍历进行对比,集合则可以使用集合的Contains函数来查询是否含有特定权限。
优点:
1.插入和删除权限很容易。
2.可以容纳任意个权限。
缺点:
1.编辑困难。
2.验证也很麻烦需要遍历,性能不高。
第三种方法:
在程序建立一个Flags型的枚举。
如:
public enum Power : long
{
None = 0x00000000, //无权限
User_Add = 0x00000001, //添加用户
User_Edit = 0x00000002, //编辑用户
User_Delete = 0x00000004, //删除用户
User_ALL = 0x00000007, //添加、编辑、删除用户
News_Add = 0x00000008, //添加新闻
News_Edit = 0x00000010, //编辑新闻
News_Delete = 0x00000020, //删除新闻
News_ALL = 0x00000038, //添加、编辑、删除新闻
Admin_Add = 0x00000040, //添加管理员
Admin_Edit = 0x00000080, //编辑管理员
Admin_Delete = 0x00000100, //删除管理员
Admin_ALL = 0x000001C0 //添加、编辑、删除管理员
}
数据库中只需要一个bigint字段来存储,实体类则可以用一个Power型的属性来表示。验证方法就非常简单了用位运算符 & 来验证,如:
1。验证单个权限
User.Power & power1 == power1
2。验证多个权限
Power power1 = Power.Admin_Delete;
Power power2 = Power.News_Edit ;
User.Power & (power1 | power2) == (power1 | power2);
//方法二:
Power power1 = Power.Admin_Delete | Power.News_Edit;
User.Power & power1 == power1;
如果结果是真 则代表有这个权限。
设置权限的方法是用位运算符中的|来设置,如:
就可以给用户设置User_ALL、News_ALL、Admin_Add这三个权限,而User_ALL包含了User_Add、User_Edit、User_Delete。News_ALL包含了News_Add、News_Edit、News_Delete。
如果还有什么不明白的可以看看MSDN中对Flags枚举的介绍。
优点:存储结构简单,数据库中使用的是数值型字段利于搜索,存储空间小。验证很容易,可以同时进行多个权限的验证,验证速度非常快性能损耗小。
缺点:可以存储的权限数量有限,只能存储64个权限(long为64位数,每一位代表一个权限)。
我个人比较喜欢使用第三种方法,虽然数量有限但一般的开发中64个权限以及足够了而带来的便捷足以弥补此缺憾,即使超过也可以对权限分组,划分为不同的枚举存在不同的字段中。