Should I remove this question? I figured out what the issue was and it wasn't IIS... See my answer below for the outcome.
Original Question I'm working on an ASP.Net MVC app and run in to a weird issue with URL Rewrite redirects and AJAX requests.
I've added the following rewrite rule to my Web.config in the root site.
<rewrite>
<rules>
<rule name="Account" stopProcessing="true">
<match url="^SubApp/Account/(.*)$" />
<action type="Redirect" url="Account/{R:1}" redirectType="Found" />
</rule>
</rules>
</rewrite>
Everything seems to work ok if I use a Permanent
or Temporary
redirectType
in the config but fails with a HTTP Error 401.0 - Unauthorized
IIS error page .
When I make an normal GET request via the browser to an action that would trigger this rule e.g. https://some-site/SubApp/Account/Settings
then I get a 302 Found and the location header is set to the expected URL https://some-site/Account/Settings
and the appropriate page is rendered.
However when I make a GET request via JQuery's AJAX i.e. $.get('https://some-site/SubApp/Account/Settings')
the returned Response status code is 401 Unauthorized
but it still has the appropriate location header.
The content of the response is a standard IIS HTTP Error 401.0 - Unauthorized
error page.
Weirdly everything seems to work ok if I use either the Permanent
or Temporary
redirect types in the config but fails only with Found
.
/SubApp
is a separate application that sits below the root site at /
.
What's going on?
Screenshots
redirectType="Permanent"
redirectType="Found"
redirectType="Temporary"
As you can see from the screenshots the only difference is the redirectType
specified in the Web.config
.
As you can see the redirects are happening as expected with exception to the Found
redirect type which I would expect to get a 302 - Found
response redirecting to the same URL as the others.
Ahhhh, you know when you don't think about something for a while and you get hit with sudden inspiration... Well it happened last night and I found this little nugget put in place to "fix" MVC's insistance on redirecting AJAX requests when authentication fails...
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;
}
}
And, unsuprisingly, context.Request.IsAuthenticated
is always false as it appears to get reset by the redirect .
Updated this, with a little help from Branislav Abadjimarinov's blog post on the subject.
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;
}
}
}
And it all works as expected.
Only question is should I remove this question?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With