HttpStatusCodeResult (401) returns "200 OK"

Using ASP.NET MVC 5, I would like to return the appropriate HTTP status code for different scenarios (401 for the user is not authenticated, 403 when the user does not have the right to any resource, etc.) and then processes them in jQuery .

But the problem is that when I try to return 401, it always returns "200: OK". MVC 5 RC1 gave โ€œ302: Foundโ€ instead of 401, so I could use a workaround ( HttpStatusCodeResult (401) returns โ€œ302 Found . โ€ But now I switched from MVC 5 RC1 to MVC 5, and this behavior has changed. Now it's always โ€œ200: OK.โ€ So my workaround is useless, of course, I cannot replace 200 with anything else.

public ActionResult My() { if (User.Identity.IsAuthenticated == false) { return new HttpStatusCodeResult(401, "User is not authenticated."); // Returns "200: OK" } // ... other code ... } 

How to solve this?

+8
c # asp.net-mvc asp.net-mvc-5
source share
5 answers

The MVC 5+ pipe modifies 401 response codes.

Option 1 with .net 4.5

you can set HttpContext.Response.SuppressFormsAuthenticationRedirect to true.

eg. in your custom AuthoriseAttribute.cs

  protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { if (filterContext.HttpContext.Request.IsAjaxRequest()) { filterContext.Result = new JsonResult { Data = "_Logon_", JsonRequestBehavior = JsonRequestBehavior.AllowGet }; filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized; filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true; } 

Option 2. If you are not using .net 4.5

  public class SuppressFormsAuthenticationRedirectModule : IHttpModule { private static readonly object SuppressAuthenticationKey = new object(); public static void Register() { DynamicModuleUtility.RegisterModule( typeof(SuppressFormsAuthenticationRedirectModule)); } public static void SuppressAuthenticationRedirect(HttpContext context) { context.Items[SuppressAuthenticationKey] = true; } public static void SuppressAuthenticationRedirect(HttpContextBase context) { context.Items[SuppressAuthenticationKey] = true; } public void Init(HttpApplication context) { context.PostReleaseRequestState += OnPostReleaseRequestState; context.EndRequest += OnEndRequest; } public void Dispose() { } private void OnPostReleaseRequestState(object source, EventArgs args) { var context = (HttpApplication)source; var response = context.Response; var request = context.Request; if (response.StatusCode == 401 && request.Headers["X-Requested-With"] == "XMLHttpRequest") { SuppressAuthenticationRedirect(context.Context); } } private void OnEndRequest(object source, EventArgs args) { var context = (HttpApplication)source; var response = context.Response; if (context.Context.Items.Contains(SuppressAuthenticationKey)) { response.TrySkipIisCustomErrors = true; response.ClearContent(); response.StatusCode = 401; response.RedirectLocation = null; } } } 

and in web.config

  <modules> <add name="SuppressFormsAuthenticationRedirectModule" type="SuppressFormsAuthenticationRedirectModule"/> </modules> 

See here for more details.

+3
source

A solution to the problem can be found at http://kevin-junghans.blogspot.in/2013/12/returning-401-http-status-code-on.html

You need to change the Startup class as follows:

 public partial class Startup { private static bool IsAjaxRequest(IOwinRequest request) { IReadableStringCollection query = request.Query; if ((query != null) && (query["X-Requested-With"] == "XMLHttpRequest")) { return true; } IHeaderDictionary headers = request.Headers; return ((headers != null) && (headers["X-Requested-With"] == "XMLHttpRequest")); } // For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864 public void ConfigureAuth(IAppBuilder app) { // Enable the application to use a cookie to store information for the signed in user app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new PathString("/Account/Login"), Provider = new CookieAuthenticationProvider { OnApplyRedirect = ctx => { if (!IsAjaxRequest(ctx.Request)) { ctx.Response.Redirect(ctx.RedirectUri); } } } }); // Use a cookie to temporarily store information about a user logging in with a third party login provider app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); } 

}

+2
source

I am using simuler code that returns 404. Your code could be:

 public ActionResult My() { if (User.Identity.IsAuthenticated == false) { return new HttpUnauthorizedResult(); } // ... other code ... } 
0
source

For Identity middleware, redirection can be disabled by removing the LoginPath parameter in Startup.Auth.cs:

  public void ConfigureAuth(IAppBuilder app) { app.UseCookieAuthentication(new CookieAuthenticationOptions { ... LoginPath = new PathString("/Account/Login"), // Remove this line }); 
0
source

In Statup.cs, I had to set AutomaticChallenge to false . As soon as I did this, he stopped URL redirecting (which led to 200 status) and gave me the 401 status that I wanted.

 public void ConfigureServices(IServiceCollection services) { services.AddIdentity<ApplicationUser, ApplicationRole>(options => { options.Cookies.ApplicationCookie.AutomaticChallenge = false; //<@@@@@@@ //... }) .AddEntityFrameworkStores<ApplicationDbContext, int>() .AddDefaultTokenProviders(); } 

If you set the cookie middleware:

 public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IAntiforgery antiforgery) { app.UseCookieAuthentication(new CookieAuthenticationOptions() { AuthenticationScheme = "__auth__", LoginPath = "/account/login", AccessDeniedPath = "/account/forbidden", AutomaticAuthenticate = true, AutomaticChallenge = false //<@@@@@@@ }); } 
0
source

All Articles