ASP.NET MVC用户友好401错误

时间:2009-11-05 11:17:47

标签: asp.net-mvc handleerror

我在ASP.NET MVC网站in a way like suggests this post中实现了错误处理。

404错误一切正常。但如何正确显示用户友好的屏幕 401错误?它们通常不会抛出可在Application_Error()内处理的异常,而是返回HttpUnauthorizedResult。一种可能的方法是将以下代码添加到Application_EndRequest()方法

的末尾
if (Context.Response.StatusCode == 401)
{
    throw new HttpException(401, "You are not authorised");
    // or UserFriendlyErrorRedirect(new HttpException(401, "You are not authorised")), witout exception
}

但是在Application_EndRequest()内部Context.Session == null,errorController.Execute()失败,因为它无法使用默认的TempDataProvider。

  // Call target Controller and pass the routeData.
  IController errorController = new ErrorController();
  errorController.Execute(new RequestContext(    
       new HttpContextWrapper(Context), routeData)); // Additional information: The SessionStateTempDataProvider requires SessionState to be enabled.

那么,您能否建议一些最佳实践如何在ASP.NET MVC应用程序中使用“用户友好句柄”?

感谢。

4 个答案:

答案 0 :(得分:14)

查看HandleErrorAttribute。从中获取子类或添加您自己的实现,它将处理您感兴趣的所有状态代码。您可以使它为每种错误类型返回单独的错误视图。

以下是如何创建句柄错误异常过滤器的想法。我抛弃了大部分内容,只专注于我们的必需品。绝对看看原始实现添加参数检查和其他重要的事情。

public class HandleManyErrorsAttribute : FilterAttribute, IExceptionFilter
{
    public virtual void OnException(ExceptionContext filterContext)
    {
        if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled)
            return;

        Exception exception = filterContext.Exception;

        string viewName = string.Empty;
        object viewModel = null;
        int httpCode = new HttpException(null, exception).GetHttpCode();
        if (httpCode == 500)
        {
            viewName = "Error500View";
            viewModel = new Error500Model();
        }
        else if (httpCode == 404)
        {
            viewName = "Error404View";
            viewModel = new Error404Model();
        }
        else if (httpCode == 401)
        {
            viewName = "Error401View";
            viewModel = new Error401Model();
        }

        string controllerName = (string)filterContext.RouteData.Values["controller"];
        string actionName = (string)filterContext.RouteData.Values["action"];
        filterContext.Result = new ViewResult
        {
            ViewName = viewName,
            MasterName = Master,
            ViewData = viewModel,
            TempData = filterContext.Controller.TempData
        };
        filterContext.ExceptionHandled = true;
        filterContext.HttpContext.Response.Clear();
        filterContext.HttpContext.Response.StatusCode = httpCode;

        filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
    }
}

然后用这个属性“装饰”你的控制器动作:

[HandleManyErrors]
public ActionResult DoSomethingBuggy ()
{
    // ...
}

答案 1 :(得分:6)

我设法以一种非常简单的方式解决了这个问题。我想为登录用户显示一个自定义页面(“你没有权限bla bla ...”)并将未经身份验证的用户重定向到登录页面(默认行为)。 所以我实现了一个自定义AuthorizeAttribute(比如说CustomAuthorizeAttribute),其HandleUnauthorizedRequest方法被覆盖,如果用户被认证,我将filterContext参数的Result属性设置为一个名为AccessDenied.aspx的ViewResult(在Shared文件夹中)

protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
    if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
    {
        base.HandleUnauthorizedRequest(filterContext);
    }
    else
    {
        filterContext.Result = new ViewResult { ViewName = "AccessDenied" };
    }
}

然后你必须使用这个新属性。 问候。

答案 2 :(得分:0)

如果您正在使用ASP.NET MVC,那么您很可能使用IIS,那么为什么不设置IIS以使用该Web应用程序/虚拟目录的自定义401错误页面?

答案 3 :(得分:-1)

在我的一个项目中,我使用uvita中的代码。

我有 ASP.NET MVC2 ,我在没有登录页面的情况下使用 Active Directory 身份验证。 我有一个使用网站母版页的 NoAuth.aspx 页面,整合了网络应用程序布局。

这是web.config。

<system.web>
    <authentication mode="Windows" />
    <roleManager enabled="true" defaultProvider="AspNetWindowsTokenRoleProvider">
       <providers>
          <clear />
          <add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider"
          applicationName="/" />
      </providers>
    </roleManager>
</system.web>

新类CustomAutorizeAttribute

using System.Web.Mvc;
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
        {
            base.HandleUnauthorizedRequest(filterContext);
        }
        else
        {
           filterContext.Result = new ViewResult { ViewName = "NoAuth"};
        }
    }
}

和控制器

[CustomAuthorize(Roles = "ADRole")]
public class HomeController : Controller
{
    public HomeController()
    {
    }
}