c# - mvc - HttpStatusCodeResult(401) devuelve "200 OK"
return http error c# (5)
Utilizando ASP.NET MVC 5, me gustaría devolver el código de estado HTTP apropiado para diferentes escenarios (401 para el usuario no está autenticado, 403 cuando el usuario no tiene derecho a algún recurso, etc.), y luego manejarlos en jQuery.
Pero el problema es que cuando intento devolver 401, siempre devuelve "200: OK". MVC 5 RC1 estaba dando "302: Encontrado" en lugar de 401, por lo que podría usar una solución alternativa ( HttpStatusCodeResult (401) devuelve "302 Encontrado" ). Pero ahora pasé de MVC 5 RC1 a MVC 5 y este comportamiento cambió. Ahora siempre es "200: OK". Entonces mi solución no sirve para nada, por supuesto que no puedo reemplazar 200 con nada más.
public ActionResult My()
{
if (User.Identity.IsAuthenticated == false)
{
return new HttpStatusCodeResult(401, "User is not authenticated.");
// Returns "200: OK"
}
// ... other code ...
}
¿Cómo resolver esto?
En Statup.cs tuve que configurar AutomaticChallenge
en false
. Una vez que lo hice, dejó de hacer el redireccionamiento de URL (que dio como resultado el estado 200) y me dio el estado 401 que deseaba.
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentity<ApplicationUser, ApplicationRole>(options =>
{
options.Cookies.ApplicationCookie.AutomaticChallenge = false; //<@@@@@@@
//...
})
.AddEntityFrameworkStores<ApplicationDbContext, int>()
.AddDefaultTokenProviders();
}
Si ha configurado algún middleware de cookies:
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 //<@@@@@@@
});
}
La solución al problema se puede encontrar en http://kevin-junghans.blogspot.in/2013/12/returning-401-http-status-code-on.html
Debes modificar tu clase de Startup
esta manera:
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);
}
}
La tubería MVC 5+ modifica los códigos de respuesta 401.
Opción 1 con .net 4.5
puede establecer HttpContext.Response.SuppressFormsAuthenticationRedirect
en true.
por ejemplo, en su CustomiseAttribute.cs personalizado
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;
}
Opción 2. Si no usa .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;
}
}
}
y en web.config
<modules>
<add name="SuppressFormsAuthenticationRedirectModule" type="SuppressFormsAuthenticationRedirectModule"/>
</modules>
Para el middleware Identity, el redireccionamiento se puede deshabilitar eliminando en la opción LoginPath en Startup.Auth.cs:
public void ConfigureAuth(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
...
LoginPath = new PathString("/Account/Login"), // Remove this line
});
Utilizo el código simuler que arroja 404. Su código podría ser:
public ActionResult My()
{
if (User.Identity.IsAuthenticated == false)
{
return new HttpUnauthorizedResult();
}
// ... other code ...
}