65.9K
CodeProject 正在变化。 阅读更多。
Home

在具有 Windows 身份验证的 ASP.NET 应用程序中,“访问被拒绝”时重定向到自定义 401 页面

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.67/5 (15投票s)

2005年8月3日

3分钟阅读

viewsIcon

359782

downloadIcon

2393

本文回答了一个简单的问题:当 web.config 中 401 错误的自定义错误页面不起作用时该怎么办?如何替换默认的 ASP.NET“访问被拒绝”页面?

引言

如果您有一个 ASP.NET 应用程序,并将身份验证模式设置为 Windows

 <authentication mode="Windows"/> 
 <authorization>
         <deny users="?" />
 </authorization>

那么所有 Windows 用户都可以访问您的页面,但那些没有 Windows 登录(来自互联网)的用户将收到一个 ASP.NET“访问被拒绝 401”页面。我决定用一个自定义页面替换这个默认消息。经过几个小时的搜索,我发现这是一个非常普遍的问题,而且所有看起来合理的解决方法都不起作用。以下是一些方法:

  1. Web.config 中使用自定义错误页面
    <customErrors defaultRedirect="ErrorPage.asp&shy;x" mode="On"> 
        <error statusCode="401" redirect="AccessDenied.aspx" />       
    </customErrors>

    这在使用 statusCode="404" 时工作正常,但对于 401 则无效。

  2. 尝试在 Global.asax.cs 的某个应用程序事件中捕获未经授权的请求
    protected void Application_AuthenticateRequest(Object sender, 
                                                        EventArgs e)
    {
     if (!Request.IsAuthenticated) Response.Redirect(
                                                "AccessDenied.aspx"); 
    }

    这也没有用,因为即使是具有有效凭据的浏览器也会发送两个 POST 请求,一个不带凭据且 Request.IsAuthenticated=false,另一个带凭据且 Request.IsAuthenticated=true。不带凭据的浏览器只发送一个 POST 请求。这意味着您无法确定第一个 Request.IsAuthenticated=false 的 POST 请求是来自未经授权的浏览器还是其他情况。

问题所在

然后,我从 microsoft.public.dotnet.framework.aspnet.security 新闻组的一位专家那里得到了一个答案。

这是正确的。没有办法绕过它。Wininet 身份验证的工作方式是,如果您请求的资源不允许匿名访问,则会向浏览器发送一个 401 响应。如果资源使用 Windows 集成身份验证并且浏览器配置为自动发送凭据,则会发送令牌并验证用户身份。对于基本身份验证,将显示登录提示,并且用户必须登录。

如果您拦截 401 并重定向到其他地方,您就会劫持浏览器的挑战能力。没有办法绕过它。

Jxx Cxxxxxx, MCSE, MCSD [MSFT], Developer Support, ASP.NET。

分辨率

这也是我研究的结果。整个过程如下:

  1. 浏览器在没有凭据的情况下向服务器发送请求。
  2. 服务器拒绝此请求并返回“401 访问被拒绝”响应。
  3. 浏览器识别出 401,如果它具有适当的凭据,则不会显示此消息。将发送带有凭据的第二个请求。请求的页面将被发送到浏览器。
  4. 如果浏览器 **没有凭据**,则不会发生第二个 POST 请求。将显示收到的“401 访问被拒绝”消息。

解决方法是操纵“401 访问被拒绝”响应的内容。浏览器使用此响应的标头来确定 401 情况。这意味着我们可以操纵 HTML 内容而不影响整个挑战。例如,我们可以在 Global.asax.csApplication_EndRequest 事件中添加以下代码。

  protected void Application_EndRequest(Object sender, 
                                             EventArgs e)
  { 
     HttpContext context = HttpContext.Current;
     if (context.Response.Status.Substring(0,3).Equals("401"))
     {
        context.Response.ClearContent();
        context.Response.Write("<script language="javascript">" + 
                     "self.location='../login.aspx';</script>");
     } 
  }

现在,整个过程如下:

  1. 浏览器在没有凭据的情况下向服务器发送请求。
  2. 服务器拒绝此请求并返回“401 访问被拒绝”标头 + 我们的 JavaScript。
  3. 浏览器识别出 401,如果它具有适当的凭据,则不会显示此消息。我们的 HTML 不会被渲染,JavaScript 也不会被执行。将发送带有凭据的第二个请求。请求的页面将被发送到浏览器。
  4. 如果浏览器 **没有凭据**,则不会发生第二个 POST 请求。将显示收到的“401 访问被拒绝”。我们的 HTML 将被渲染,JavaScript 将被执行。将发生客户端重定向。浏览器将显示自定义 401 页面。

示例项目

示例项目在 Global.asax.csApplication_EndRequest 事件中只有几行相关的代码。default.aspx 页面仅对授权的 Windows 用户可访问。如果访问被拒绝,将调用 PublicArea/AccessDenied.aspx 页面。根据本地 Web.configPublicArea 文件夹也对匿名用户可访问。

注意:IIS 网站必须配置为允许匿名访问。

© . All rights reserved.