简体   繁体   中英

customerrors for 401.2 in ASP.NET

I successfully implemented role based authorization in ASP.NET. When a person does not have the needed role he gets to see an error page for 401.2 not authorized.

What I would like to accomplish now is to have a custom 401 page in my application and have it redirected there via settings in the web.config. I tried this:

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

But this does not get caught. Do I have to override it in IIS instead? I hope not as that would make getting things deployed harder.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM