HttpStatusCodeResult(401)返回“200 OK”

时间:2013-11-17 18:02:47

标签: c# asp.net asp.net-mvc http-status-codes asp.net-mvc-5

使用ASP.NET MVC 5,我想为不同的场景返回适当的HTTP状态代码(401用户未经过身份验证,403当用户无权使用某些资源时等),然后在jQuery中处理它们。

但问题是,当我尝试返回401时,它总是返回“200:OK”。 MVC 5 RC1给出了“302:Found”而不是401,所以我可以使用一种解决方法(HttpStatusCodeResult(401) returns "302 Found")。 但是现在我从MVC 5 RC1转移到了MVC 5,这种行为发生了变化。现在它总是“200:OK”。所以我的解决方法毫无用处,当然我不能用其他任何东西替换200。

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

   // ... other code ...
}

如何解决这个问题?

5 个答案:

答案 0 :(得分:4)

MVC 5+ Pipeline修改了401响应代码。

选项1使用.net 4.5

您可以将HttpContext.Response.SuppressFormsAuthenticationRedirect设置为true。

e.g。在您的自定义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;
        }

选项2.如果不使用.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;
        }
    }
}

和web.config

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

See here for more info

答案 1 :(得分:3)

可以在http://kevin-junghans.blogspot.in/2013/12/returning-401-http-status-code-on.html

中找到问题的解决方案

您需要像这样修改Startup类:

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 :(得分:1)

我使用返回404的simuler代码。您的代码可能是:

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

答案 3 :(得分:0)

对于Identity中间件,可以通过在Startup.Auth.cs中删除LoginPath选项来禁用重定向:

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

答案 4 :(得分:0)

在Statup.cs中,我必须将AutomaticChallenge设置为false。一旦我这样做,它就停止了URL重定向(导致200状态),并给了我所需的401状态。

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

如果你设置了一些cookie中间件:

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  //<@@@@@@@
    });
}
相关问题