ASP.NET MVC 用户友好的 401 错误

发布于 2024-08-10 07:31:57 字数 1156 浏览 10 评论 0原文

我已经在 ASP.NET MVC 站点 以类似于本文建议的方式

出现 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 应用程序中“用户友好地处理”401 的最佳实践?

谢谢。

I have implemented errors handling in ASP.NET MVC site in a way like suggests this post.

With 404 errors all works fine. But how correctly show user friendly screen for a 401 error? They usually do not throw Exception that can be handled inside Application_Error() but rather action returns HttpUnauthorizedResult. One possible way is to add following code to the end of Application_EndRequest() method

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

But inside Application_EndRequest() Context.Session == null, errorController.Execute() fails because it cannot use default 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.

So, can you suggest some best practices how to 'user friendly handle' 401 in ASP.NET MVC application?

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

绻影浮沉 2024-08-17 07:31:57

查看 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 ()
{
    // ...
}

Look at the HandleErrorAttribute. Subclass from it or add your own implementation which will handle all the status codes you're interested in. You can make it to return a separate error view for each error type.

Here is an idea of how to create your handle error exception filter. I've thrown out most of the stuff to only focus on our essentials. Absolutely have a look at the original implementation to add arguments checks and other important things.

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;
    }
}

Then you "decorate" your controller actions with this attribute:

[HandleManyErrors]
public ActionResult DoSomethingBuggy ()
{
    // ...
}
鸵鸟症 2024-08-17 07:31:57

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

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

然后您必须请改用这个新属性。
问候。

I managed to solve this in a very simple way. I wanted to show a custom page for logged-in users ("you have no permission bla bla...") and redirect unauthenticated users to the login page (the default behaviour).
So I implemented a custom AuthorizeAttribute (say CustomAuthorizeAttribute) with the HandleUnauthorizedRequest method overwritten in a way that if the user is authenticated I set the Result property of the filterContext argument with a ViewResult (in the Shared folder) called AccessDenied.aspx

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

Then you have to use this new attribute instead.
Regards.

≈。彩虹 2024-08-17 07:31:57

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

If you're using ASP.NET MVC, you're more than likely to use IIS, so why don't you just set up IIS to use your custom 401 error page for that Web Application / Virtual Directory?

逐鹿 2024-08-17 07:31:57

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

我有 ASP.NET MVC2,并且使用 Active Directory 身份验证,无需登录页面。
我有一个 NoAuth.aspx 页面,它使用网站母版页,集成 Web 应用程序布局。

这是 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()
    {
    }
}

In one of my project, I use the code from uvita.

I have ASP.NET MVC2 and I use Active Directory authentication without login page.
I have a NoAuth.aspx page that use site master page, integrate the web application layout.

This is the 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>

The new class 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"};
        }
    }
}

and the controller

[CustomAuthorize(Roles = "ADRole")]
public class HomeController : Controller
{
    public HomeController()
    {
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文