How to return 401 instead of 302 in ASP.NET Core?

2019-01-13 21:57发布

问题:

I'm trying to get ASP.NET Core Identity to return 401 when a user isn't logged in. I've added an [Authorize] attribute to my method and instead of returning 401 it returns 302. I've tried a ton of suggestions but nothing seems to work, including services.Configure and app.UseCookieAuthentication setting LoginPath to null or PathString.Empty.

回答1:

As of ASP.NET Core 2.x:

services.ConfigureApplicationCookie(options =>
{
    options.Events.OnRedirectToLogin = context =>
    {
        context.Response.StatusCode = 401;    
        return Task.CompletedTask;
    };
});


回答2:

If the request header contains X-Requested-With: XMLHttpRequest the status code will be 401 instead of 302

private static bool IsAjaxRequest(HttpRequest request)
    {
        return string.Equals(request.Query["X-Requested-With"], "XMLHttpRequest", StringComparison.Ordinal) ||
            string.Equals(request.Headers["X-Requested-With"], "XMLHttpRequest", StringComparison.Ordinal);
    }

See on gitHub: https://github.com/aspnet/Security/blob/5de25bb11cfb2bf60d05ea2be36e80d86b38d18b/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieAuthenticationEvents.cs#L40-L52



回答3:

services.Configure<IdentityOptions>(options =>
{
   options.Cookies.ApplicationCookie.LoginPath = new PathString("/");
   options.Cookies.ApplicationCookie.Events = new CookieAuthenticationEvents()
   {
      OnRedirectToLogin = context =>
      {
         if (context.Request.Path.Value.StartsWith("/api"))
         {
            context.Response.Clear();
            context.Response.StatusCode = 401;
            return Task.FromResult(0);
         }
         context.Response.Redirect(context.RedirectUri);
         return Task.FromResult(0);
      }
   };
});

Source:

https://www.illucit.com/blog/2016/04/asp-net-5-identity-302-redirect-vs-401-unauthorized-for-api-ajax-requests/



回答4:

For Asp.net Core 2 USE THIS INSTEAD

services.ConfigureApplicationCookie(options =>
{
    options.LoginPath = new PathString("/Account/Login");
    options.LogoutPath = new PathString("/Account/Logout");

    options.Events.OnRedirectToLogin = context =>
    {
        if (context.Request.Path.StartsWithSegments("/api")
            && context.Response.StatusCode == StatusCodes.Status200OK)
        {
            context.Response.Clear();
            context.Response.StatusCode = StatusCodes.Status401Unauthorized;
            return Task.FromResult<object>(null);
        }
        context.Response.Redirect(context.RedirectUri);
        return Task.FromResult<object>(null);
    };
});


回答5:

Okay after digging around in the asp.net core unit tests I finally found a working solution. You have to add the following to your call to services.AddIdentity

services.AddIdentity<ApplicationUser, IdentityRole>(o => {
    o.Cookies.ApplicationCookie.AutomaticChallenge = false;
});