Bookmark and Share

Lee's 程序人生

HTML CSS Javascript XML AJAX ATLAS C# C++ 数据结构 软件工程 设计模式 asp.net Java 数字图象处理 Sql 数据库
  博客园  :: 首页  :: 新随笔  :: 联系 :: 管理

基于操作+角色的授权方案(具体实现篇)

Posted on 2009-09-12 14:00  analyzer  阅读(212)  评论(0编辑  收藏  举报

接上文,上一篇随笔说了基于操作+角色授权方案的设计思路,本随笔谈谈如何实现,可以方便高效的使用此方案。

在这套授权方案中角色是用户可配置的,而操作是死的,我们在程序中实现了什么功能就有什么样的操作,所以我们充分利用这一点,为了使用方便我们将操作作为PageBase(项目中统一的Page基类)的Attribute来定义,然后在PageBase对应页面执行PreLoad事件时读取此页面上定义的Attribute属性中的操作,然后读取当前用户可执行的操作,对比得到用户是否有访问该页面的权限。
ActionsAttribute的实现很简单,就是定义了一个只读的string数组来存放页面功能中的操作。其实现如下:

[global::System.AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public sealed class ActionsAttribute : Attribute
{
    
public readonly string[] PageActions;


    
public ActionsAttribute(params string[] actions)
    {
        PageActions 
= actions;
    }
}

我们需要在PageBase类中实现对ActionsAttribute(即当前页实现操作)的读取和对权限的判断,关键代码如下


protected override void OnInit(EventArgs e)
{
     PreLoad 
+= new EventHandler(IfNoPermission);
base.OnInit(e);
}
protected static Type _permissionAttributeType = typeof(ActionsAttribute);
protected string[] _actions = null;
private static Dictionary<Type, string[]> _pageActionsDict = new Dictionary<Type, string[]>();
protected string[] _allowedRoles = null;
protected virtual bool CanEnterPage()
{
    
if (_actions == null)
    {
        Type t 
= this.GetType();
        
if (_pageActionsDict.ContainsKey(t))
        {
            _actions 
= _pageActionsDict[t];
        }
        
else
        {
            
object[] attributes = t.GetCustomAttributes(_permissionAttributeType, true);
            
if (attributes != null && attributes.Length > 0)
            {
                List
<string> actionList = new List<string>();
                
foreach (object attr in attributes)
                {
                    ActionsAttribute actionsAttr 
= attr as ActionsAttribute;
                    
if (actionsAttr != null && actionsAttr.PageActions != null && actionsAttr.PageActions.Length > 0)
                    {
                        actionList.AddRange(actionsAttr.PageActions);
                    }
                }
                _actions 
= actionList.ToArray();
            }
            
else
            {
                _actions 
= new string[] { };
            }
#if !DEBUG
            
if (_pageActionsDict.ContainsKey(t) == false)
            {
                _pageActionsDict.Add(t, _actions);
            }
#endif
        }
    }

    
if (_actions != null && _actions.Length > 0)
    {
        
return LoginUser.CanDoAction(_actions);
    }
    
return true;
}

protected virtual void RedirectIfHasNoPermission()
{
    Response.Redirect(
"~/error/permission.htm"true);
}

protected virtual void IfNoPermission(object sender, EventArgs e)
{
    
if (!CanEnterPage())
    {
        RedirectIfHasNoPermission();
    }
}
大家都知道读取Attribute是通过反射来做的,其性能会有问题,所以我们生命了一个静态的成员变量_pageActionsDict来保存解析出来的Attribute和Page类型的对应字典,这样所有页面的Attribute都仅需要读取一遍,对性能几乎没有影响。
在上面的方法中我们使用了LoginUser.CanDoAction方法,其中LoginUser是PageBase的一个属性,表示当前登录的用户,在User类中有对当前用户权限的判断。其相关代码如下:

/// <summary>
/// 判断用户是否具有某几个角色中的一种
/// </summary>
/// <param name="roleNames">几种角色</param>
/// <returns>true拥有一种,否则没有</returns>
public bool CanDoAction(params string[] actions)
{
    
return true;
}

/// <summary>
/// 判断当前用户是有对某资源执行某种操作的权限
/// </summary>
/// <param name="boardId">版面id</param>
/// <param name="action">操作</param>
/// <returns>true:有权限,false:无权限</returns>
public bool CanDoAction(int boardId, string action)
{
    
return true;
}

这两个方法没有具体实现,不过有了设计思路实现是很简单的。

我们在具体使用中,就是直接给具体的Page类加上Attribute了,如下示例代码:

    [Actions(ActionsConst.EnterAdmin)]
    
public partial class Default : PageBase
    {
        
protected void Page_Load(object sender, EventArgs e)
        {
            
        }
    }

 

其中ActionsConst是系统中所有操作的常量定义类。

全文完。



请尊重作者的劳动,转载请保留链接 玉开的技术博客      

我要啦免费统计