使用 Windows 2008r2、IIS 7.5,我有一个使用 Windows 集成身份验证(WWW-Authenticate:NTLM,Negotiate)的应用程序。
在我的 ASP.NET MVC 代码中,我正在覆盖 IIS 错误页面输出...
protected void Application_EndRequest(Object sender, EventArgs e)
{
HttpContext context = ((HttpApplication)sender).Context;
if (context.Response.Status.Substring(0, 3).Equals("401"))
{
HttpApplication app = (HttpApplication)sender;
string returnUrl = Response.ApplyAppPathModifier("~/OpenId/AskUser").ToString();
string url = new Uri(this.Request.Url, Response.ApplyAppPathModifier("~/Account/Login?returnUrl=" + returnUrl)).ToString();
app.Response.ClearContent();
app.Response.Write(string.Format("<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"utf-8\"><meta http-equiv=\"refresh\" content=\"0;URL='{0}'\"><title>Error Authenticating</title><script language=\"javascript\">self.location='{0}';</script></head><body>Error Authenticating</body></html>", url));
}
}
目标是,如果用户使用非 Windows 计算机或移动设备(或在 Windows PC 上使用 Firefox),则将用户重定向到他们可以使用的基于表单的登录,而不是通过 Windows 集成身份验证获取 Windows 凭据。
我在服务器上使用 IIS 7.5 时遇到的问题是,即使触发了此 EndRequest 事件(我可以从插入代码并观察 fiddler 的 X-DEBUG 标头中看出),发送回客户端的 HTML 输出是 IIS 7.5 默认错误页面,用于 http 状态代码 401,而不是我输出的 HTML 页面。第一次发送请求(第一个带有 401 响应的请求)时,它工作正常,但如果用户使用空的或错误的用户名/密码组合单击“确定”,则后续的 401 响应不会在响应正文中包含正确的输出(默认的 IIS 7.5 401 响应页面或简单的文本句子而没有 HTML)。
请注意,这不会发生在我的开发人员框中的 IIS 7.5 Express 上 - 它正确地从上面的代码段输出 HTML 页面。仅当我将项目部署到 IIS 7.5 Web 服务器时才会发生这种情况。
我还尝试创建自定义错误页面...在我的 web.config 中,我在 system.webServer 下添加了以下内容...
<httpErrors>
<remove statusCode="401"/>
<error statusCode="401" prefixLanguageFilePath="" path="ErrorPages/401.html" responseMode="File" />
</httpErrors>
并创建和部署相应的 HTML 文件。完成此操作后,我不再收到默认的 IIS 7.5 错误页面,而是只收到以下简洁的纯文本(非 HTML)回复:“您无权查看此目录或页面。”。
我不明白为什么 IIS Express 可以正确输出所有内容,而 IIS 7.5 却不行。即使我告诉 IIS 7.5 针对此类错误输出不同的页面,它仍然不会这样做。
答案1
这似乎是https://stackoverflow.com/questions/434272/iis7-overrides-customerrors-when-setting-response-statuscode,但是我对 Server Fault 还不太熟悉,无法标记此问题。
我的看法:我在 IIS 服务器上使用 Mediawiki 时遇到了类似的问题。
当您浏览 Mediawiki 中不存在的页面时。它会发回一个特殊的 wiki 页面,表示该页面不存在并允许您创建它。但是,该页面发送时的状态为 404。
在标准 IIS 服务器上,IIS 会自动用自定义错误页面覆盖此页面,供不在本地主机上的用户查看,但会向本地主机上的用户发送详细的错误消息。实际上,“详细错误消息”意味着让原始错误页面通过,无论它是应用程序中自定义的还是由于编码错误由 ASP.NET 生成的。
我的方法是在“错误页面”>“功能”设置中为本地和远程用户启用详细的错误消息。但是,这也将允许远程用户在发生 ASP 错误时看到详细的错误消息,这可能会帮助恶意用户破坏您的安全。
链接问题的答案中给出了其他选项,包括可能不涉及安全问题的更好选项。在这种情况下,另一个选项是不返回 401 状态代码,而只是使用自定义页面返回普通的 200 代码。这牺牲了 REST 原则以简化开发。
请注意,对本地用户显示详细的错误消息,但不对远程用户显示详细的错误消息,这也许可以解释为什么您的解决方案在本地测试期间有效,但在部署时却无效。