在MVC3中抛出错误页--HttpException
最近在用MVC实现一些权限管理方面的东西,大概思路是继承AuthorizeAttribute写了一个子类UserAuthorizeAttribute,在需要验证的Action或controller中引用该Attribute。重写了三个方法,依执行顺序分别是OnAuthorization -> AuthorizeCore -> HandleUnauthorizedRequest。
在OnAutorization中获取特性标记的方法的区域名、控制器名、操作方法名。在AuthorizeCore中判断用户是否已经登陆,若没登陆直接返回false,如果登陆则判断该用户对应的areaName、controllerName、actionName是否有访问权限(记录在数据库),有则返回true,否则设置Response.StatusCode=403,并返回false。
在HandleUnauthorizedRequest中判断如果Response.StatusCode==403则提示用户没该权限,否则调用base.HandleUnauthorizedRequest跳转到登陆页。
public override void OnAuthorization(AuthorizationContext filterContext) { actionName = filterContext.ActionDescriptor.ActionName; controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName; areaName = filterContext.RouteData.DataTokens["area"] as string; base.OnAuthorization(filterContext); } protected override bool AuthorizeCore(HttpContextBase httpContext) { if (httpContext == null) throw new ArgumentNullException("HttpContext"); if (!httpContext.User.Identity.IsAuthenticated) return false;//没有登陆 ActionRoles = ServiceFactory.SystemModuleService.GetActionRoles(actionName, controllerName, areaName); UserRoles = HttpContextHelper.GetCurrentUserRoles();//获取当前用户角色 if (ActionRoles != null && UserRoles != null && UserRoles.Any(x => ActionRoles.Contains(x))) return true; httpContext.Response.StatusCode = 403; return false; } protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { if (filterContext == null) throw new ArgumentNullException("filterContext"); //if(filterContext.HttpContext.Request.IsAjaxRequest()) switch (filterContext.HttpContext.Response.StatusCode) { case 403: filterContext.Result = new RedirectResult("~/Error/Forbidden"); break; default: base.HandleUnauthorizedRequest(filterContext); break; } }
其中在HandleUnauthorizedRequest中直接跳转到"~/Error/Forbidden",总给我一种很莫名的感觉,理想中是出现下图这样的效果,然后由web.config中指定的customError去处理:
尝试过用设置filterContext.Result=new HttpUnauthorizedResult()或者filterContext.Result=new HttpStatusCodeResult(..),HttpStatusCodeResult都不行,返回的都是空白页面。
后在stackoverflow中找到一篇这样的文章:How to return a view for HttpNotFound() in ASP.Net MVC 3? 才得以解决,其实就是一句话:
case 403: throw new HttpException(403, "Forbidden");//直接抛出403,由customErrors决定如何处理.
写到这里,惭愧,那个惭愧啊~~~
顺便贴下代码,用烂笔头记下customErrors的设置及具体实现:
<customErrors mode="On" > <error statusCode="400" redirect="~/Error/BadRequest" /> <error statusCode="403" redirect="~/Error/Forbidden" /> <error statusCode="404" redirect="~/Error/NotFound" /> <error statusCode="408" redirect="~/Error/Timeout" /> <error statusCode="500" redirect="~/Error/InternalServerError" /> <error statusCode="503" redirect="~/Error/ServiceUnavailable" /> </customErrors>
我没有设置defaultRedirect是我认为全局的HandleErrorAttribute会引用Share下的Error.cshtml帮我处理。我用一个ErrorController来实现以上错误的处理:
/// <summary> /// 403 /// </summary> public virtual ActionResult Forbidden() { ViewBag.ExceptionIco = "icon-error-forbidden"; ViewBag.ErrorDescription = "您所处的用户组没有权限访问该功能。"; return View("Index"); } /// <summary> /// 404 /// </summary> public virtual ActionResult NotFound() { ViewBag.ExceptionIco = "icon-error-notfound"; ViewBag.ErrorDescription = "您请求的页面不存在。"; return View("Index"); } .....