IIS 的奇怪 AJAX 重定向 401 问题

Weird AJAX redirect 401 issue with IIS

我应该删除这个问题吗? 我弄清楚问题出在哪里,但不是 IIS...请参阅下面的答案以了解结果。

原题 我正在开发一个 ASP.Net MVC 应用程序,并且 运行 遇到了 URL 重写重定向和 AJAX 请求的奇怪问题。

我已将以下重写规则添加到根站点中的 Web.config。

<rewrite>
    <rules>
        <rule name="Account" stopProcessing="true">
            <match url="^SubApp/Account/(.*)$" />
            <action type="Redirect" url="Account/{R:1}" redirectType="Found" />
        </rule>
    </rules>
</rewrite>

如果我在配置中使用 PermanentTemporary redirectType 似乎一切正常,但失败并出现 HTTP Error 401.0 - Unauthorized IIS 错误页面。

当我通过浏览器向会触发此规则的操作发出正常的 GET 请求时,例如https://some-site/SubApp/Account/Settings 然后我得到一个 302 Found 并且位置 header 设置为预期的 URL https://some-site/Account/Settings 并呈现适当的页面。

然而,当我通过 JQuery 的 AJAX 发出 GET 请求时,即 $.get('https://some-site/SubApp/Account/Settings') 返回的响应状态代码是 401 Unauthorized 但它仍然有适当的位置 header。

响应的内容是一个标准的 IIS HTTP Error 401.0 - Unauthorized 错误页面。

奇怪的是,如果我在配置中使用 PermanentTemporary 重定向类型,一切似乎都正常,但仅在 Found.

时失败

/SubApp 是一个单独的应用程序,位于 /.

的根站点下方

怎么回事?

截图

redirectType="Permanent"

redirectType="Found"

redirectType="Temporary"

正如您从屏幕截图中看到的,唯一的区别是 Web.config 中指定的 redirectType

如您所见,重定向按预期发生,但 Found 重定向类型除外,我希望得到 302 - Found 响应重定向到与其他。

看看这个 Cannot handle 302 redirect in ajax and why? [duplicate],网络浏览器似乎看到了 Found-302 并对其执行了操作。

啊啊啊,你知道当你暂时不去想某件事时,你会突然受到灵感的打击......好吧,它发生在昨晚,我发现这个小金块放在 "fix" MVC 坚持在身份验证失败时重定向 AJAX 请求...

protected void Application_EndRequest()
{
    var context = new HttpContextWrapper(Context);
    // MVC retuns a 302 for unauthorized ajax requests so alter to request status to be a 401
    if (context.Response.StatusCode == 302 && context.Request.IsAjaxRequest() && !context.Request.IsAuthenticated)
    {   
        context.Response.Clear();
        context.Response.StatusCode = 401;
    }
}

而且,不出所料,context.Request.IsAuthenticated 总是错误的,因为它似乎被重定向重置了。

Branislav Abadjimarinov's blog post 对该主题的一点帮助下更新了此内容。

protected void Application_EndRequest()
{
    var context = new HttpContextWrapper(Context);
    // MVC returns a 302 for unauthorized ajax requests so alter to request status to be a 401

    if (context.Response.StatusCode == 302 && context.Request.IsAjaxRequest())
    {
        //Unfortunately the redirect also clears the results of any authentication
        //Try to manually authenticate the user...
        var authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
        if (authCookie != null)
        {
            var authTicket = FormsAuthentication.Decrypt(authCookie.Value);
            if (authTicket != null && !authTicket.Expired)
            {
                var roles = authTicket.UserData.Split(',');
                HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(new FormsIdentity(authTicket), roles);
            }
        }

        if (!context.Request.IsAuthenticated)
        {
            context.Response.Clear();
            context.Response.StatusCode = 401;
        }

    }
}

一切都按预期进行。

唯一的问题是我应该删除这个问题吗?