.NET core returning 500 instead of 401 when missing cookie

纵然是瞬间 提交于 2019-12-23 01:39:06

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!