问题
I have a .NET core API that uses cookie authentication. It is accessed by a PWA/SPA that has its own login route.
In Startup.cs
:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddIdentity<MyUser, MyRole>(options =>
{
...
// Use cookie authentication
var expiresIn = new TimeSpan(1, 0, 0); // 1 hour timeout
var c = options.Cookies.ApplicationCookie;
c.AuthenticationScheme = "appSchemeName";
c.CookieName = "appCookieName";
c.AutomaticAuthenticate = true;
// If this is true auth failures become redirects
c.AutomaticChallenge = false;
c.SlidingExpiration = true;
c.ExpireTimeSpan = expiresIn;
// Store sessions in the cache with the same TTL as the cookie
c.SessionStore = new MyRedisSessionStore(expiresIn);
});
...
}
public void Configure(...)
{
...
app.UseIdentity();
...
app.UseMvc();
}
In my client side JS I expect a 401 when the authentication cookie is invalid or missing, and display a login form when this is the case.
However, when a user without a valid cookie visits a controller flagged with [Authorize]
they get a 500 status error:
InvalidOperationException: No authentication handler is configured to handle the scheme: Automatic
If I change c.AutomaticChallenge = true;
then I get a 302 redirecting to {site}/Account/Login?ReturnUrl={api resource it was trying to load}
. That's weird because that's not a valid route and I didn't set it.
How do I fix this so that unauthenticated users get a 401 instead of a 500 exception on the server.
I realise that I can override this and write my own authentication with custom responses, but there must be a way to make the built-in [Authorize]
return the correct HTTP status code.
回答1:
I ran into this exact issue when I was using Postman to test my endpoints.
If you look at the source code for the OnRedirectToLogin
event, you can see that it is checking if the request is an AJAX request. For IsAjaxRequest
to return true
, the X-Requested-With
header needs to have XMLHttpRequest
as it's value.
If you happen to be testing this out with Postman, you'll have to manually apply the X-Requested-With along with the correct value:
Finally, this is what your CookieAuthenticationOptions
should look like if you have no other special configurations that need to be set:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true
});
回答2:
I have a fix for this, as in I have code that works, but it's horrible and cannot possibly be the best way to handle this.
My current code give me either a 500 server error (when AutomaticChallenge = false
), or a 302 redirect (when AutomaticChallenge = true
). Both are useless in my SPA because 500 is too generic and the 302 redirects transparently to a non-existent page and I get a 404 in the client side JS.
My fix is to go with the 302 and then override the Response
:
// Make ASP.NET give us the 302 redirect when cookie is missing/broke
c.AutomaticChallenge = true;
c.Events = new CookieAuthenticationEvents
{
// Override the 302 redirection with the 401 we actually want
OnRedirectToLogin = context =>
{
context.Response.StatusCode = 401;
return Task.FromResult(0); ;
}
};
This works and so it it an answer to this question, but it's a horrible hack around middleware that isn't behaving how I want it to.
来源:https://stackoverflow.com/questions/43662305/net-core-returning-500-instead-of-401-when-missing-cookie