Web下的授权简单解决方案(Asp.Net)

Web下的授权简单解决方案(Asp.Net) 


Author:
蛙蛙池塘

From: cnblogs
web下的授权简单解决方案
【permission】表结构 
【id】 int identity(1,1) not null PK:权限编号,自增列 
【title】narchar(50):权限名称 
【parentid】 int:父类ID 
【url】varchar(500):菜单的链接地址 
【state】 int: 状态字段,0表示菜单,1是具体权限 
 
身份验证 
用户表或者角色表里加一个权限集【permissionSet】的字段,里面存放着用逗号隔开的权限ID,表示一个权限的集合,用户进行身份验证后把权限字符串保存在FormsAuthenticationTicket.UserData里,或者保存在Session["permission"]里。 
 
利用菜单实现简单授权 
问题:我们的后台管理一般都有导航系统,各种角色登陆后这个导航菜单显示的元素是不一样的,是根据权限来显示的。我们先解决这个问题。 
一般来说是一个树型的菜单,我们用微软的IE WebControls Treeview来做导航,先定义一个方法,代码如下。 
 
public void AddTree(string ParentID,TreeNode pNode,TreeView tvn) 

    DataSet ds = this.GetSqlSet("SELECT * FROM permission ORDER BY id where state = 0"); 
    DataView dvTree = new DataView(ds.Tables[0]); 
 
    //过滤ParentID,得到当前的所有子节点 
    dvTree.RowFilter = "parentid ='" ParentID "'"; 
    foreach(DataRowView Row in dvTree) 
    { 
        TreeNode Node=new TreeNode() ; 
        if(pNode == null) 
        {   
              //添加根节点,根节点不设置链接地址 
              Node.ID=Row["id"].ToString(); 
              Node.Text = Row["title"].ToString(); 
 
              //判断用户是否有这个功能,然后添加这个菜单, 
              if (Session["permission"].ToString().IndexOf("," Row["id"].ToString() ",")!= -1) 
                  tvn.Nodes.Add(Node); 
               
              AddTree(Row["id"].ToString(), Node,tvn);    //再次递归 
        } 
        else 
        {  //添加当前节点的子节点 
              Node.ID=Row["id"].ToString(); 
              Node.Text = Row["title"].ToString(); 
              Node.NavigateUrl = Row["url"].ToString(); 
              Node.Target = "main"; 
               
              //授权检查 
              if (Session["permission"].ToString().IndexOf("," Row["id"].ToString() ",")!= -1) 
                  pNode.Nodes.Add(Node); 
 
 
              AddTree(Row["id"].ToString(),Node,tvn);    //再次递归 
        } 
    } 

 
加载菜单用AddTree("0",null,this.Tree1)就可以了。 
注意,如果你让用户没有一个大类菜单的访问权限,却让它有这个大类菜单的小类的访问权限,这个菜单也不能显示,因为递归不到那里去。 
问题:现在不该显示的菜单是不显示了,但是不能防止用户直接在地址栏里输入路径访问页面,下面我们来解决这个问题 
实现页面访问权限检查 
 
在页面基类里声明两个受保护成员,如下 
protected string pageAccess; //页面访问权限字符串 
protected bool isChkAccess = false; //本页是否执行访问权限检查,默认不执行检查 
在页面基类的Load事件里调用下面的方法 
void chkAccess() 

    if (Session["permission"].ToString().IndexOf("," this.pageAccess ",") == -1 &;amp;&;amp; this.isChkAccess) 
    { 
        Response.Write("你没有访问该页的权限"); 
        Response.End(); 
    } 

让所有的页面继承自你写的自定义页面基类,并在页面的构造函数里启用页面访问权限检查并设置访问权限ID,代码如下 
this.isChkAccess = true; //启用页面权限检查 
this.pageAccess = "6"; //设置页面访问权限字符串为6,实际上是黄页信息管理权限。 
 
问题:现在恶意用户直接敲击地址也不能访问不该访问的页面了,但是有时候一个页面上不同的角色呈现的页面也是不一样的,比如同样的黄页管理页面,有些人可以审核,有些人不能审核,我们要动态的判断是否显示审核黄页的按钮 
 
实现细粒度授权检查 
 
还是在页面基类里添加一个方法,用来执行权限的断言。代码如下 
public bool chkPermission(string permission) 

    string permissionid = this.GetSqlScalar("select id from permission where state = 1 and title = '" permission "'").ToString(); 
    return Session["permission"].ToString().IndexOf("," permissionid ",") != -1; 
 

其中GetSqlScalar也是页面基类里定义的一个快速执行数据库操作的方法,然后你可以在具体的页面的LOAD方法里动态的设置某个UI是否显示。 
Trace.Write("检查审核黄页的权限",this.chkPermission("审核黄页").ToString()); 
this.Button1.Visible = this.chkPermission("审核黄页"); 
 
上面的Button1就是审核黄页的按钮。 
 
不足之处: 
1、这里没有考虑用户,角色,权限集等概念,只是做了一些授权的简单实现,没有提供完整的RBAC方案。 
2、这里的资源继承关系没有考虑进去,也就是子菜单是否继承父菜单的访问许可设置。 
3、这里没有定义黑名单和白名单的高级授权内容。 
4、这里没有显式定义每个资源的允许和拒绝权限,以及权限的计算策略。 
5、这里没有考虑一个用户同时属于多个角色时的权限检查策略。 
6、这里没有考虑用户的部门概念,关于组织机构概念,也没有提到,尽管这是权限系统设计的必要因素。 
 
小节:有了这个接口后,再做一个用户,角色,权限的管理界面就可以了,这些的管理的都是对数据库的添加,修改,删除操作,比较简单了。主要是把权限集绑定到角色,(多对多)然后把用户绑定到角色(多对多),剩下的,就是用户登陆的时候根据角色这个链接表,读取它能获取哪些权限集,把这些权限集合并起来,就是这个用户的权限集了。 
    (2006-4-05:05:36)

 感谢原创者的辛勤劳动,希望对您有所帮助,转载请注明原出处。
 您可能对 [Asp.Net] 的这些文章也感兴趣:

ASP.NET2.0中控件的简单异步回调
深入剖析ASP.NET的编译原理之一:动态编译(Dynamical Compilation)
用ASP.Net获取客户端网卡的MAC
如何在窗体和窗体之间传送数据
Asp.net Mvc Preview 5 体验:ActionSelectionAttribute
.Net程序如何防止被注入(整站通用)
实时天气及24小时天气预报
ASP.NET 2.0 中的 Windows 身份验证
解读ASP.NET 2.0 Internals
ASP.NET中实时图表的实现