这种方法基于这样的数学原理:
1)(2 | 4 | 16 | 32 | 256) & (4 | 32) == (4 | 32)
2)Sigma ( 2n , n 是自然数 ) = 2n+1 - 1 ,即 1 + 2 + 4 + 8 + .... + 64 = 128 - 1 = 127
这种方法的好处是存储形态简单,仅存储一个整型数值。
代价是权限位的数量受语言的 Int 整数类型可处理位数的限制。即如果权限位的数量在 32 以下,就可以使用 Convert.ToInt32() 转换和存储;超过 32 位就要使用 Convert.ToInt64() 了;比 64 更多就没办法存储了。
存取测试
/// 烹饪材料
/// </summary>
public enum Stuff
{
水 = 1,
米 = 2,
皮蛋 = 4,
姚柱 = 8,
瘦肉 = 16,
腊味 = 32,
糯米 = 64,
盐 = 128,
味精 = 256,
}
/// <summary>
/// 权限存储测试
/// </summary>
[Test]
public void StorePermissionTest()
{
// 我有这些材料
Stuff[] userStuffs = new Stuff[] {Stuff.水 , Stuff.米 , Stuff.瘦肉 , Stuff.腊味 , Stuff.盐 };
Stuff stuffCollection = (Stuff) 0;
foreach(Stuff stuff in userStuffs)
{
stuffCollection = stuffCollection | stuff;
}
// 通过『与』运算得到『我拥有什么材料』的数值封装
Console.WriteLine(Convert.ToInt32(stuffCollection));
}
/// <summary>
/// 权限校验测试
/// </summary>
/// <param name="userStuff">我拥有什么材料</param>
/// <param name="cookbook">烹饪需要的材料</param>
/// <returns>如果我拥有烹饪需要的全部材料,则返回 true;否则返回 false</returns>
public bool isValid( Stuff userStuff, Stuff cookbook )
{
return (( userStuff & cookbook ) == cookbook);
}
/// <summary>
/// 权限提取测试
/// </summary>
[Test]
public void RestorePermissionsTest()
{
// 曾经通过『与』运算得到『我拥有什么材料』的数值封装
int stuffs = 179;
// 还原为材料枚举
Stuff userStuff = (Stuff) stuffs;
// 做白粥需要的材料
Stuff congee = Stuff.水 | Stuff.米 | Stuff.盐 ;
// 看来可以做白粥 哦 ^_^
Console.WriteLine( this.isValid(userStuff, congee) );
// 做皮蛋瘦肉粥需要的材料
Stuff congeePreservedEgg = Stuff.水 | Stuff.米 | Stuff.盐 | Stuff.皮蛋 | Stuff.瘦肉 ;
// 看来不可以皮蛋瘦肉粥了 >_<
Console.WriteLine( this.isValid(userStuff, congeePreservedEgg) );
}
授权方式
/// 添加权限测试
/// </summary>
public void AddPermissionTest()
{
// 曾经通过『与』运算得到『我拥有什么材料』的数值封装
int stuffs = 179;
// 还原为材料枚举
Stuff userStuff = (Stuff) stuffs;
Stuff addStuff = Stuff.水 | Stuff.糯米 ;
// 只加入了糯米
userStuff = userStuff | addStuff ;
}
/// <summary>
/// 丢弃权限测试
/// </summary>
public void RemovePermissionTest()
{
// 曾经通过『与』运算得到『我拥有什么材料』的数值封装
int stuffs = 179;
// 还原为材料枚举
Stuff userStuff = (Stuff) stuffs;
Stuff dropStuff = Stuff.水 | Stuff.盐 | Stuff.糯米 ;
// 丢弃了水和盐
userStuff = userStuff ^ (dropStuff & userStuff );
}
系统权限更新后用户权限更新的方式
1. 系统删除或添加某种权限后,在权限修改记录表中存储以下权限修正操作信息:对权限的操作类型(移除、添加)、权限值、执行日期时间
2. 用户信息表中记录最后更新权限的日期时间
3. 用户登入系统时,从权限修改记录表中获取自上次用户更新权限至今需要执行的权限修正操作,依次完成权限修正后把权限值持久化回系统,同时在用户信息表中记录本次更新权限的日期时间(如果没有要执行的权限修正操作,则忽略这两步)
source: http://www.cnblogs.com/HeroBeast/archive/2008/02/01/1061281.html
C# 位运算符 http://blog.csdn.net/happyxiaochen/archive/2007/03/30/1546029.aspx
运算符号
|
意义
|
运算对象类型
|
运算结果类型
|
对象数
|
实例
|
~
|
位逻辑非运算
|
整型,字符型
|
整型
|
1
|
~a
|
&
|
位逻辑与运算
|
2
|
a & b
|
||
|
|
位逻辑或运算
|
2
|
a | b
|
||
^
|
位逻辑异或运算
|
2
|
a ^ b
|
||
<<
|
位左移运算
|
2
|
a<<4
|
||
>>
|
位右移运算
|
2
|
a>>2
|
常用的位运算主要有与(&), 或(|)和非(~), 比如:
1 & 0 = 0, 1 | 0 = 1, ~1 = 0
在设计权限时, 我们可以把权限管理操作转换为C#位运算来处理.
第一步, 先建立一个枚举表示所有的权限管理操作:
- [Flags]public enum Permissions{
- Insert = 1,
- Delete = 2,
- Update = 4,
- Query = 8}
[Flags]表示该枚举可以支持C#位运算, 而枚举的每一项值, 我们用2的n次方来赋值, 这样表示成二进制时刚好是1 = 0001, 2 = 0010, 4 = 0100, 8 = 1000等, 每一位表示一种权限, 1表示有该权限, 0表示没有.
接下来是权限的运算:
1. 权限的加法, 使用与运算来实现. 我们知道, 0001 | 0100 = 0101, 这样就表示同时具有第一位和第三位的权限管理了, 枚举表示为:
Permissions per = Permissions.Insert | Permissions.Update
2. 权限的减法, 使用与运算+非运算来实现, 如上面要去掉Insert权限, 操作为:
Permissions per &= ~Permissions.Insert即是 0101 & ~0001 = 0101 & 1110 = 0100
3. 权限的判断, 使用与运算, 当判断用一用户是否具有该操作权限时, 要把用户的的权限与操作权限进行与运算, 如果得到的结果仍是操作权限管理, 则表示用户具有该权限:
- Permissions per = Permissions.Insert | Permissions.Update;
- if(per & Permissions.Insert = Permissions.Insert)
- {
- //有操作权限
- }
比较过程为 0101 & 0001 = 0001, 0001的0位用与C#位运算把其它位都置成0, 变成只比较1的这一位.