customerrors for 401.2 in ASP.NET

梦想的初衷 提交于 2019-11-29 14:05:39

I ran into the same problem recently and it turns out that this is one of the quirks when using Windows Authentication.

Joshua Flanagan created a nice HttpModule a while ago that will respect the customErrors section in your web.config and redirect to the 401 error page.

The key to the solution is to intercept the EndRequest event of the page lifecycle, check for a 401 status code, and then execute your custom page.

The portability of the HttpModule is nice because it makes the solution reusable, and keeps your Global.asax clean, but there's nothing stopping you from wiring up your EndRequest event in the Global.asax with his code if you really wanted to.

If you're using ASP.NET MVC, the solution isn't quite as elegant.

If you do not want to add an HttpModule

in web.config

<system.web>
    <customErrors mode="On" defaultRedirect="~/MyController/MyErrorAction/" redirectMode="ResponseRedirect">
      <error statusCode="401" redirect="~/MyController/MyErrorAction/" />
    </customErrors>

in global.asax.cs

    protected void Application_EndRequest(object sender, EventArgs e)
    {
        HttpApplication application = (HttpApplication)sender;

        if (application.Response.StatusCode != 401 || !application.Request.IsAuthenticated) return;

        application.Response.ClearContent();

        //You can replace the piece below is to redirect using MVC, or your can replace all this with application.Server.Execute(yourPage);
        IController errorController = new SharedController();
        var rd = new RouteData();
        rd.Values.Add("controller", "MyController");
        rd.Values.Add("action", "MyErrorAction");
        rd.Values.Add("value", "You or your user group do not have permissions to use the address: " + Request.Url.PathAndQuery);

        errorController.Execute(new RequestContext(new HttpContextWrapper(Context), rd));
        HttpContext.Current.Server.ClearError();
    }

Here's an MVC agnostic variant:

In Web.config

<customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
    <error statusCode="401" redirect="NoAccess.htm" />
</customErrors>

In Global.asax.cs

protected void Application_EndRequest(object sender, EventArgs e)
{
    HttpApplication application = (HttpApplication)sender;

    if (application.Response.StatusCode != 401 || !application.Request.IsAuthenticated) return;

    var customErrors = (CustomErrorsSection)ConfigurationManager.GetSection("system.web/customErrors");

    var accessDeniedPath = customErrors.Errors["401"] != null ? customErrors.Errors["401"].Redirect : customErrors.DefaultRedirect;
    if (string.IsNullOrEmpty(accessDeniedPath))
        return; // Let other code handle it (probably IIS).

    application.Response.ClearContent();
    application.Server.Execute(accessDeniedPath);
    HttpContext.Current.Server.ClearError();
}

Here's what worked well for me.

Global.asax -

    protected void Application_EndRequest(object sender, EventArgs e)
    {
        if (Response.StatusCode == 401 && Request.IsAuthenticated)
        {
            Response.StatusCode = 303;
            Response.Clear();
            Response.Redirect("~/AccessDenied.html");
            Response.End();
        }
    }

Web.config -

  <system.web>
    <customErrors mode="On">
      <error statusCode="401" redirect="AccessDenied.html"/>
    </customErrors>
    <authentication mode="Windows"/>
  </system.web>
  <location path="AccessDenied.html">
    <system.web>
      <authorization>
        <allow roles="*"/>
      </authorization>
    </system.web>
  </location>
  <location path=".">
    <system.web>
      <authorization>
        <allow roles="YourADGroup"/>
        <deny users="*" />
      </authorization>
    </system.web>
  </location>

This takes care of the double 401 before a 200 issue as well. Also circumvents the pesky firefox authentication popup.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!