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






4.67/5 (15投票s)
2005年8月3日
3分钟阅读

359782

2393
本文回答了一个简单的问题:当 web.config 中 401 错误的自定义错误页面不起作用时该怎么办?如何替换默认的 ASP.NET“访问被拒绝”页面?
引言
如果您有一个 ASP.NET 应用程序,并将身份验证模式设置为 Windows
<authentication mode="Windows"/>
<authorization>
<deny users="?" />
</authorization>
那么所有 Windows 用户都可以访问您的页面,但那些没有 Windows 登录(来自互联网)的用户将收到一个 ASP.NET“访问被拒绝 401”页面。我决定用一个自定义页面替换这个默认消息。经过几个小时的搜索,我发现这是一个非常普遍的问题,而且所有看起来合理的解决方法都不起作用。以下是一些方法:
- 在 Web.config 中使用自定义错误页面
<customErrors defaultRedirect="ErrorPage.asp­x" mode="On"> <error statusCode="401" redirect="AccessDenied.aspx" /> </customErrors>
这在使用
statusCode="404"
时工作正常,但对于 401 则无效。 - 尝试在 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。
分辨率
这也是我研究的结果。整个过程如下:
- 浏览器在没有凭据的情况下向服务器发送请求。
- 服务器拒绝此请求并返回“401 访问被拒绝”响应。
- 浏览器识别出 401,如果它具有适当的凭据,则不会显示此消息。将发送带有凭据的第二个请求。请求的页面将被发送到浏览器。
- 如果浏览器 **没有凭据**,则不会发生第二个 POST 请求。将显示收到的“401 访问被拒绝”消息。
解决方法是操纵“401 访问被拒绝”响应的内容。浏览器使用此响应的标头来确定 401 情况。这意味着我们可以操纵 HTML 内容而不影响整个挑战。例如,我们可以在 Global.asax.cs 的 Application_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>");
}
}
现在,整个过程如下:
- 浏览器在没有凭据的情况下向服务器发送请求。
- 服务器拒绝此请求并返回“401 访问被拒绝”标头 + 我们的 JavaScript。
- 浏览器识别出 401,如果它具有适当的凭据,则不会显示此消息。我们的 HTML 不会被渲染,JavaScript 也不会被执行。将发送带有凭据的第二个请求。请求的页面将被发送到浏览器。
- 如果浏览器 **没有凭据**,则不会发生第二个 POST 请求。将显示收到的“401 访问被拒绝”。我们的 HTML 将被渲染,JavaScript 将被执行。将发生客户端重定向。浏览器将显示自定义 401 页面。
示例项目
示例项目在 Global.asax.cs 的 Application_EndRequest
事件中只有几行相关的代码。default.aspx 页面仅对授权的 Windows 用户可访问。如果访问被拒绝,将调用 PublicArea/AccessDenied.aspx 页面。根据本地 Web.config,PublicArea 文件夹也对匿名用户可访问。
注意:IIS 网站必须配置为允许匿名访问。