随笔 - 35  文章 - 0  评论 - 210 

本示例演示了在ASP.NET MVC中进行基于URL的权限控制,由于是基于URL进行控制的,所以只能精确到页。这种权限控制的优点是可以在已有的项目上改动极少的代码来增加权限控制功能,和项目本身的耦合度低,并且实现起来也比较简单。缺点是权限控制不够精确,不能具体到某一具体的按钮或者某一功能。

在数据库中新建2个表。PermissionItem表用于保存权限ID和页面路径的关系,一个权限ID可以有多个页面,一般同一个权限ID下的页面是为了实现同一个功能。PermissionList表用于保存用户所具有的权限。

 

Code

数据库中的示例表示Page1和Page4同属于权限1,Page2和Page5同属于权限2,Page3属于权限3。用户ID为1的用户具有权限2和3。

在ASP.NET MVC项目中新建一个AccountHelper类,这是一个辅助类。GetPermissionItems方法用于获取权限ID和页面路径的对应关系。这是全局的,并且每个用户在访问页面时都会用到这些信息,所以存入Cache中。数据库的相关操作这里使用的是ADO.NET Entity Framework。

 

 1/// <summary>
 2/// 获取权限项
 3/// </summary>
 4/// <returns>权限项列表</returns>

 5public static List<PermissionItem> GetPermissionItems()
 6{
 7     // 如果缓存中已经存在权限列表信息,则直接从缓存中读取。
 8      if (HttpContext.Current.Cache["PermissionItems"== null)
 9     {
10          // 如果缓存中没有权限列表信息,则从数据库获取并写入缓存
11           UrlAuthorizeEntities db = new UrlAuthorizeEntities();
12          var items = db.PermissionItem.Where(c => c.PermissionID > 0).ToList();
13          HttpContext.Current.Cache["PermissionItems"= items;
14     }

15
16     // 这个缓存中保存了所有需要进行权限控制的页面所对应的权限ID
17     return (List<PermissionItem>)HttpContext.Current.Cache["PermissionItems"];
18}

19

 

GetUserPermission方法是将用户所具有的权限ID保存到一个一维Int32数组中。这个信息每个用户是不同的,但是会经常使用到,所以存入Session。

 

 1/// <summary>
 2/// 获取用户权限
 3/// </summary>
 4/// <param name="userID">用户ID</param>
 5/// <returns>用户权限数组</returns>

 6public static Int32[] GetUserPermission(int userID)
 7{
 8    // 如果缓存中已经存在权限列表信息,则直接从缓存中读取。
 9    if (HttpContext.Current.Session["Permission"== null)
10    {
11        // 从数据库获取用户权限并将权限ID放到int数组并存入Session
12        UrlAuthorizeEntities db = new UrlAuthorizeEntities();
13        var permissions = db.PermissionList.Where(c => c.UserID == userID).Select(c=>c.PermissionID).ToArray();
14        HttpContext.Current.Session["Permission"= permissions;
15    }

16    return (Int32[])HttpContext.Current.Session["Permission"];
17}

18

 

再新建一个UrlAuthorizeAttribute类,继承自AuthorizeAttribute,这是一个Filter。我们重写它的OnAuthorization方法,以在ASP.NET页生命周期身份验证阶段执行它。

 

 1/// <summary>
 2/// 重写OnAuthorization
 3/// </summary>
 4/// <param name="filterContext"></param>

 5public override void OnAuthorization(AuthorizationContext filterContext)
 6{
 7    // 获取权限项列表
 8    List<PermissionItem> pItems = AccountHelper.GetPermissionItems();
 9
10    // 获取当前访问页面对应的权限ID。如果item为空则表示当前页面没有权限控制信息,不需要进行权限控制
11    var item = pItems.FirstOrDefault(c => c.Route == filterContext.HttpContext.Request.Path);
12
13    if (item != null)
14    {
15        if (Array.IndexOf<Int32>(AccountHelper.GetUserPermission(int.Parse(filterContext.HttpContext.Session["UserID"].ToString())), item.PermissionID) == -1)
16        {
17            // 提示权限不够,也可以跳转到其他页面
18            filterContext.HttpContext.Response.Write("没有权限访问该页面");
19            filterContext.HttpContext.Response.End();
20        }

21    }

22    else
23    {
24        // 如果权限项列表中不存在当前页面对应的权限ID则所有用户都不允许访问,直接提示无权访问。***注1***
25        filterContext.HttpContext.Response.Write("没有权限访问该页面");
26        filterContext.HttpContext.Response.End();
27    }

28}

29

 

至此,主要的工作都已经完成了的。接下来我们只需要在需要进行权限控制的Action或Controller前加上[UrlAuthorize],这些Action或Controller中的所有Actions就会自动被UrlAuthorize这个Filter进行处理。如果某一个Action被标上了[UrlAuthorize],而数据库中又不存在该页面对应的权限ID,那么根据示例的代码,所有用户都将无法访问这个页面,如果需要更改这个设置,可以修改上面“注1”下面的2行代码。

示例代码下载
 

本文适用于 ASP.NET MVC 1.0

 

Tag标签: ASP.NET,MVC
0
0
(请您对文章做出评价)
« 上一篇:Windows Vista SP2 和 Windows Server 2008 SP2 已经发布
» 下一篇:在使用 ADO.NET Entity Framework 时生成的实体类个数少于数据表个数的几种情况及原因分析
posted on 2009-07-07 08:58 Snowdream 阅读(3799) 评论(18)  编辑 收藏 网摘 所属分类: ASP.NET

  回复  引用  查看    
#1楼 2009-07-07 09:24 | James.Ying      
非常不错,收藏下
楼主的博客设计的很漂亮,是博客园的模板吗?

  回复  引用    
#2楼 2009-07-07 09:28 | MSHQ[未注册用户]
很时髦,呵呵,不感冒
  回复  引用  查看    
#3楼[楼主] 2009-07-07 09:34 | Snowdream      
@James.Ying
是在博客园原有的模版上修改的 :)

  回复  引用  查看    
#4楼 2009-07-07 10:18 | gguozhenqian      
好东西!!!
  回复  引用  查看    
#5楼 2009-07-07 10:18 | gguozhenqian      
啊啊啊啊啊啊啊啊啊啊啊
  回复  引用  查看    
#6楼 2009-07-07 11:57 | Der      
东西先收下了
LZ的代码排版很好看,也很实用,怎么弄的啊?

  回复  引用  查看    
#7楼[楼主] 2009-07-07 12:05 | Snowdream      
@Der
添加文章的编辑器里有个code按钮的~按了就可以插入代码了的~

  回复  引用  查看    
#8楼 2009-07-07 19:23 | 紫色永恒      
good,mark
  回复  引用  查看    
#9楼 2009-08-01 14:41 | Lyrf      
c => c.Route == filterContext.HttpContext.Request.Path

请问这种 c=>c.Rout 这种写法是什么意思
呵呵 俺一小菜鸟 不懂哦
看到好多人都用这种写法 不知道有什么优势 可以在哪得到相关的学习资料呢?

  回复  引用  查看    
#10楼[楼主] 2009-08-01 14:54 | Snowdream      
@Lyrf
这是Lambda表达式~MSDN中有关于这个的介绍(http://msdn.microsoft.com/zh-cn/library/bb397687.aspx)~优势也没什么优势~就是看起来简洁一些~
c => c.Route == filterContext.HttpContext.Request.Path中=>的左边是参数~c的类型是PermissionItem~=>右边是表达式~判断参数c的Route属性与filterContext.HttpContext.Request.Path是否相等~

  回复  引用    
#11楼 2009-08-26 13:35 | Kagilo[未注册用户]
把path改成 controller 和 action 不是更好?
urlrouting 也不用怕了~~~ 直接针对 controller 和 action.

  回复  引用  查看    
#12楼[楼主] 2009-08-26 15:36 | Snowdream      
@Kagilo
恩~是可以这样的~稍稍改动一下就行:)

  回复  引用  查看    
#13楼 2010-02-01 09:51 | Tso      
老大,我试着做了一遍,发现并不能成功啊,虽然你有示例下载,但是我是VS2010+MVC2,根本就不能运行啊。你可以再用MVC2实现一次吗。
  回复  引用  查看    
#14楼[楼主] 2010-02-01 18:06 | Snowdream      
@Tso
本文中的代码和示例是根据ASP.NET MVC 1.0给出的~所以可能无法在MVC 2.0环境下运行~
你可以根据文中的方法~结合自己的需要~在自己的环境下试试~如果碰到具体问题~可以再提出来讨论~

  回复  引用  查看    
#15楼 2010-02-01 23:53 | Tso      
楼主,谢谢你回复,我用的是VS2010+MVC2,我试着做了一下,但是现在又发现,你的教程里有的Controller中的TestController.cs中的写法令我感到有点奇怪,现在的写法是这样的:
        [UrlAuthorize]
        public ActionResult Tso()
        {
            return View();
        }

为什么你写的是这样的:
        [UrlAuthorize]
        public string Page1()
        {
            return "Page1";
        }

        [UrlAuthorize]
        public string Page2()
        {
            return "Page2";
        }
……

可你写的这个在MVC2中无法运行的,因为无法创建VIEW页面。
所以请问:
下面这些代码如何更改才能运行呢,另外我发现那个登陆代码也根本不管作用啊,请你检查一下,你的教程确实可以运行吗?
 /// <summary>
        /// 登陆页
        /// </summary>
        /// <returns></returns>
        public string SignIn()
        {
            // 用户登陆操作,这里直接将当前用户作为ID为1的用户登陆
            HttpContext.Session["UserID"] = 1;
            return "SignIn";
        }
        [UrlAuthorize]
        public ActionResult About()
        {
            return View();
        }
        [UrlAuthorize]
        public ActionResult Tso()
        {
            return View();
        }

  回复  引用  查看    
#16楼[楼主] 2010-02-02 13:08 | Snowdream      
return View()

它返回了一个ViewResult类型~ViewResult继承自ActionResult~所以返回类型可以写成ActionResult~
但是返回View()得有一个对应的视图~如View文件夹下一个aspx文件~
我写成
return "page1"

是为了方便演示~它返回一个字符串~所以返回类型是string~效果就是页面上显示一行字"Page1"相当于
Response.Write("Page1");
Response.End();

它不需要有一个View~
你出现这个问题可能是你虽然函数返回了View()但是没有对应的View(aspx文件)

  回复  引用  查看    
#17楼 2010-02-02 14:52 | Tso      
@Snowdream
你好,我是初学者,那我想请问,上面的代码,我到底要如何改变才能应用你这篇教程讲的情况吗,而且,你现在这篇教程中的情况,对于登录根本不能进行判断,盼解析。

  回复  引用  查看    
#18楼[楼主] 2010-02-02 15:00 | Snowdream      
登录页一般是所有用户都能访问的~没有[UrlAuthorize]也就不会判断用户是否有权限访问该页~
要对用户是否登录进行判断需要在OnAuthorization方法中增加这个逻辑~如果用户没有登录就跳转到登陆页~
HttpContext.Session["UserID"] = 1; 是自动登录为UserID为1的用户~可以改成返回登录页视图~