[转载]使用MvcHandler设计自定义系统权限 – RyanDing – 博客园.
本文是续上篇 使用MvcHandler设计自定义系统权限<上> 的下篇。通过本篇,我将在MVC2.0中提出一个系统权限的解决方案,如存在不足的地方,希望您能够指出。谢谢!
一、回顾上篇中的内容:
重点回顾一下上篇的3.2中的MyHandler类,该类继承MVC2.0的MvcHandler类。代码如下:
01 |
protected override System.IAsyncResult BeginProcessRequest(System.Web.HttpContext httpContext, System.AsyncCallback callback, object state) |
09 |
return base .BeginProcessRequest(httpContext, callback, state); |
贴出以上代码,着重想讲解的就是我们的权限判断应该注入在第11行,这个if语句内。将权限注入在第11行,个人认为这个权限是建立在MVC整个框 架外的。效率应该会更高,而且随着未来ASP.NET MVC版本的升级换代。这种权限结构在一定程度上是不受MVC框架的制约的,总比继承AuthorizeAttribute特性来控制权限高明一些吧?否 则那些“反reflection派”又开始出来用效率说事。
二、切入正题,将权限功能注入系统
先看以下代码:
01 |
protected override System.IAsyncResult BeginProcessRequest(System.Web.HttpContext httpContext, System.AsyncCallback callback, object state) |
06 |
string userName = httpContext.User.Identity.Name; |
08 |
if ( string .Compare(userName, "admin" , true ) == 0) |
14 |
return base .BeginProcessRequest(httpContext, callback, state); |
这里我们还是使用.NET经典的System.Security.Principal类库。从httpContext.User.Identity 获取到登录的用户名符串(从Name属性获取值)。在Login这个View内保存登录成功的用户信息,Login View 这个登录页面不需要对权限进行处理,everyone 都可以打开。后台代码如下:
1 |
FormsAuthenticationService auth = new FormsAuthenticationService(); |
2 |
auth.SignIn( "admin" , false ); |
假设admin就是当前用户,这里的admin硬编码了,应该从UI获取。
三、具体的实现思路
在MVC2.0中如果通过Action进行判断的话,难免要考虑到Area机制。因为在不同的Area中,可能会出现相同的Controller和 Action。所以在权限判断时还需要将Area加入到逻辑中一起判断。这样就可以精确的控制所有的MVC的URL。比如我们通过 AreaName + ControllerName + ActionName 这样判断就可以对系统具体的URL进行唯一标识,同时也方便处理权限了。我们将
BeginProcessRequest方法重新改造如下:
01 |
protected override System.IAsyncResult BeginProcessRequest(System.Web.HttpContext httpContext, System.AsyncCallback callback, object state) |
06 |
string userName = httpContext.User.Identity.Name; |
09 |
string strAreaName = base .RequestContext.RouteData.DataTokens[ "area" ] == null ? |
10 |
"" : base .RequestContext.RouteData.DataTokens[ "area" ].ToString(); |
13 |
string strNameSpaces = base .RequestContext.RouteData.DataTokens[ "namespaces" ] == null ? |
14 |
"" : base .RequestContext.RouteData.DataTokens[ "namespaces" ].ToString(); |
16 |
string strAction = base .RequestContext.RouteData.Values[ "action" ].ToString(); |
18 |
string strController = base .RequestContext.RouteData.Values[ "controller" ].ToString(); |
21 |
if ( string .Compare(userName, "admin" , true ) == 0) |
28 |
return base .BeginProcessRequest(httpContext, callback, state); |
从MVC RouteData 的 DataTokens得到area相关信息;Values得到action与controller相关信息,最后将获取的值再参与具体的权限判断。
四、注意事项
在整个调试的过程中,发现只有一个地方让我调试了半天:
MyHandler不能控制area的内部的Action。后来查阅相关资料,原来是在AreaRegistration(MVC2.0新增Area后自动生成的类)中设置问题。贴出代码,供参考:
1 |
public override void RegisterArea(AreaRegistrationContext context) |
3 |
context.Routes.Add( new Route( "{area}/{controller}/{action}/{id}" |
4 |
, new RouteValueDictionary( new { area = "admin" , controller = "Home1" , action = "Index" , id = "" }) |
5 |
, new RouteValueDictionary( new { area = "admin" }) |
6 |
, new RouteValueDictionary( new {area = "admin" , Namespaces = "TestMvc.Areas.admin.Controllers" }) |
7 |
, new HelloWorldHandler())); |
新增的area结构如下:
至此,您可以在MVC2.0中加入权限机制了。我相信通过这种方式注入自定义的权限结构到MVC程序中,总比用HttpModule来的强一些,因为客户端请求CSS/JS时,不需要再过滤这类的URL。代码看起会更舒服点,判断也就更简单点。
希望本篇文章可以给您带来帮助,如有不足之处欢迎指出,谢谢!