注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Simon

 
 
 

日志

 
 

角色权限,RBAC的简单实现  

2008-09-17 18:02:46|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

以上是一个简化版本关系图.

User:用户表,存放用户信息

Role:角色表,存放角色信息

UserInRole:用户角色映射表,存放用户和角色的对就关系,多对多,一个用户可以对应多个

角色,而不同的角色有一同的权限。

Permissions:权限表,不同的角色对应不同的权限。权限信息使用一个字段flag来表示,

好处是可以使用位运算来计算权限,缺点是用位标识的权限受理论值限制,如int理论上可以

标识31种不同的权限, 当然可以整加一个字段来弥补,ApplicationID标识不同的模块

Application:模块信息。

   [Flags]

     public enum Flag:long

     {

       View=1,

       Edit=2,

       Delete=4

     }

特性[Flag]告诉编译器,当编译器看到Flag枚举时,它会充许你用|(or)操作符组合枚举值,

就像二的整数幂一样,

例如 Flag Administer=Flag.View|Flag.Edit|Flag.Delete;表示三种权限的组合。

基础知识:

位运算

枚举Flag

当编译器看到Flag枚举时,它会充许你用|(or)操作符组合枚举值,

就像二的整数幂一样,

例如 Flag Administer=Flag.View|Flag.Edit|Flag.Delete;

常用操作,检查是否存在

Flag administer=Flag.View|Flag.Edit|Flag.Delete;

public bool Check(Flag administer,Flag mask)

        {

            bool bReturn = false;

            if ((administer & mask) == mask)

                bReturn = true;

            return bReturn;

        }

调用  Check(administer,Flag.Edit)将返回true.

public Flag SetBit(Flag administer,Flag mask)

        {

          return administer |= mask;

          

        }

administer |= mask;操作相当于 administer = administer |mask;

 从枚举中减去一种状态

  administer &=mask;

如 :

Flag administer=Flag.View|Flag.Edit|Flag.Delete;

如需要禁止删除权限.

administer &=Flag.Delete;

 另外,标记为flag的枚举类型,可以不设置值

   public enum Flag:long

     {

      View,

      Edit,

      Delete

     }

 如需要设置,按以下规律, View=1,Edit=2,Delete=4,Reply=8按2次方累加,为什么会这样?因为他使用二进制操作,

   当你使用 View=1,Edit=2,Delete=3,Reply=4这样的值, Flag.Delete 包含的值是Flag.Delete还是View=1|Edit=2就无从检测了.

每个用户,可以属于不同的角色不同的角色分配不同的权限,计算所有解权的所有可能的权限组合,只要有充许的权限,那么该用户既获取该权限。

在CS系统中,Permissions表合用了二个字段来标识权限.

AllowMask,DenyMask 规责是Deny优先,也就是说当权限标记为Deny那么不论是否Allow一律禁止该用户进行此项操作。

另外,像论坛类的权限设计,仅仅一个ApplicationID字段是不够用的,因为每个版块都需要设置不同的权限,来控制权限的粒度,可在增加一张Permission表,ApplicationID修改为版块ID

这样,就可以针对不同的版块设置不同的权限

好了,接下的问题是怎么和.net自带的权限系统挂钩了。。

在asp.net系统中 ,HttpContext.Current.User实现了一个接口IPrincipal,IPrincipal包含了另一个接口Identity

我们在设计User类的时候继承此接口

public class User:IPrincipal

{

    string username;

    public string Username

    {

     get{return username;}

     set{username=value;}

    }

}

实现IPrincipal接口方法

  public IIdentity Identity

        {

            get {

                if (!string.IsNullOrEmpty(username))

                    _Identity = new GenericIdentity(username,"Forums");

                return (IIdentity)_Identity;

            }

        }

public bool IsInRole(string role)

{

.....

}

怎样和asp.net挂钩呢,这里可以在登陆时做检查

if(HttpContext.Current!=null){

                User u= Users.GetUser(name);

                HttpContext.Current.User =u;

在使用时 

User u = HttpContext.Current.User as User;

当然检查用户角色可以直接用

if(HttpContext.Current.User.Identity.IsAuthenticated&&HttpContext.Current.User.IsInRole(角色名))

另外可以直接把到当用户权限策略挂接到当前线程 ,使用以下方法

    AppDomain.CurrentDomain.SetPrincipalPolicy(User);

好了,接下来,怎么check权限?

我倾向于使用Attribute

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Delegate, Inherited = true, AllowMultiple = true)]

    public class CheckPermissionAttribute : Attribute

    {

        int appID;

        public int ApplicationID

        {

            get { return appID; }

            set { appID = value; }

        }

        Permission _allMask;

        public Permission AllMask

        {

            get { return _allMask; }

            set { _allMask = value; }

        }

        public CheckPermissionAttribute(ApplicationID app, Permission allMask)

        {

            appID = app;

            _allMask = allMask;

        }

        public CheckPermissionAttribute(Permission allMask)

        {

            _allMask = allMask;

        }

    }

AttributeUsage 第一个参数表示该属性可以应用于类,方法,属性,代理上

Inherited 检查继承的权限。

AllowMultiple 充许多次应用。

按下来,设计一个基类,继承自Page:

public   class PageBase : Page

{

Flag _allMask;

/// <summary>

    /// 检查类型权限

    /// </summary>

    public void CheckClass()

    {

        Type type = this.GetType();

        CheckPermissionAttribute att = (CheckPermissionAttribute)CheckPermissionAttribute.GetCustomAttribute(type, typeof(CheckPermissionAttribute));

        if (att != null)

        {

            Check(att.AllMask);

        }

    }

/// <summary>

    /// 检查函数调用权限

    /// </summary>

    /// <param name="methodName">方法名</param>

    public void CheckMethod(string methodName)

    {

        Type type = this.GetType();

        string name = "*";

        if (!string.IsNullOrEmpty(methodName))

            name = methodName;

        MemberInfo[] mis = type.FindMembers(MemberTypes.Method ,BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.IgnoreCase,Type.FilterNameIgnoreCase,name);

        foreach (MethodInfo m in mis)

       {

           CheckPermissionAttribute att = (CheckPermissionAttribute)CheckPermissionAttribute.GetCustomAttribute(m, typeof(CheckPermissionAttribute));

           if (att != null)

           {

               Check(att.AllMask);

                          

           }

           

       }

       return;

   

    }

    public void Check(Flag permissions)

    {

        if (!CheckPermission(permissions))

        {

            string url = string.Format("MsgPage.aspx?msg={0}", HttpUtility.UrlEncode("您没有权限访问该资源"));

            Response.Redirect(url);

        }

    }

    public void Check(ApplicationID appID, Flag permissions)

    {

        PermissionManager pm= Spaces.PermissionManager.Instance(appType);

        if (!CheckPermission(pm,permissions))

        {

            string url = string.Format("MsgPage.aspx?msg={0}", HttpUtility.UrlEncode("您没有权限访问该资源"));

            Response.Redirect(url);

        }

    }

protected override void OnInit(EventArgs e)

    {

        CheckClass();

        base.OnInit(e);

    }

}

如何使用:

[CheckPermission(2, Flag.View)]

public partial class MyPage : PageBase

{

}

若没有查看权限,会自运导向错误页面。

在类上应用挺方便。

方法上应用使用递归比较麻烦:

可以调用 CheckMethod(方法名称);如

[CheckPermission(2, Flag.Delete)]

public partial class MyPage : PageBase

{

public void test()

{

   CheckMethod("test");

   .......

}

}

这是需要重复劳动的

当然有简单的方法啦,~_~

在页面class里怎么获取当前调用的对象的相关信息见博客的另外一篇文章:.http://hi.baidu.com/lingyunj/blog/item/955bab7e7a84c53c0cd7da35.html

  评论这张
 
阅读(342)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018