asp.net-mvc 使用 ASP.NET MVC 的 json 请求的 401 响应代码

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/123726/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-07 22:45:33  来源:igfitidea点击:

401 response code for json requests with ASP.NET MVC

asp.net-mvc

提问by derigel

How to disable standard ASP.NET handling of 401 response code (redirecting to login page) for AJAX/JSON requests?

如何禁用 AJAX/JSON 请求的 401 响应代码(重定向到登录页面)的标准 ASP.NET 处理?

For web-pages it's okay, but for AJAX I need to get right 401 error code instead of good looking 302/200 for login page.

对于网页来说没问题,但是对于 AJAX,我需要获得正确的 401 错误代码,而不是用于登录页面的好看的 302/200。

Update: There are several solutions from Phil Haack, PM of ASP.NET MVC - http://haacked.com/archive/2011/10/04/prevent-forms-authentication-login-page-redirect-when-you-donrsquot-want.aspx

更新: ASP.NET MVC 的 PM Phil Haack 提供了几种解决方案 - http://haacked.com/archive/2011/10/04/prevent-forms-authentication-login-page-redirect-when-you-donrsquot -want.aspx

采纳答案by Troels Thomsen

The ASP.NET runtime is developed so that it always will redirect the user if the HttpResponse.StatusCodeis set to 401, but only if the <authentication />section of the Web.config is found.

ASP.NET 运行时经过开发,因此如果HttpResponse.StatusCode设置为 401,它总是会重定向用户,但<authentication />前提是找到了 Web.config的部分。

Removing the authentication section will require you to implement the redirection to the login page in your attribute, but this shouldn't be a big deal.

删除身份验证部分将要求您在您的属性中实现到登录页面的重定向,但这应该没什么大不了的。

回答by Catalin DICU

In classic ASP.NET you get a 401 http response code when calling a WebMethod with Ajax. I hope they'll change it in future versions of ASP.NET MVC. Right now I'm using this hack:

在经典的 ASP.NET 中,当使用 Ajax 调用 WebMethod 时,您会得到 401 http 响应代码。我希望他们会在 ASP.NET MVC 的未来版本中改变它。现在我正在使用这个黑客:

protected void Application_EndRequest()
{
    if (Context.Response.StatusCode == 302 && Context.Request.Headers["X-Requested-With"] == "XMLHttpRequest")
    {
        Context.Response.Clear();
        Context.Response.StatusCode = 401;
    }
}

回答by Timothy Lee Russell

I wanted both Forms authentication and to return a 401 for Ajax requests that were not authenticated.

我想要表单身份验证并为未经身份验证的 Ajax 请求返回 401。

In the end, I created a custom AuthorizeAttribute and decorated the controller methods. (This is on .Net 4.5)

最后,我创建了一个自定义 AuthorizeAttribute 并修饰了控制器方法。(这是在 .Net 4.5 上)

//web.config

//web.config

<authentication mode="Forms">
</authentication>

//controller

//控制器

[Authorize(Roles = "Administrator,User"), Response302to401]
[AcceptVerbs("Get")]
public async Task<JsonResult> GetDocuments()
{
    string requestUri = User.Identity.Name.ToLower() + "/document";
    RequestKeyHttpClient<IEnumerable<DocumentModel>, string> client =
        new RequestKeyHttpClient<IEnumerable<DocumentModel>, string>(requestUri);

    var documents = await client.GetManyAsync<IEnumerable<DocumentModel>>();

    return Json(documents, JsonRequestBehavior.AllowGet);
}

//authorizeAttribute

//授权属性

public class Response302to401 : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
        {
            if (filterContext.HttpContext.Request.IsAjaxRequest())
            {
                filterContext.Result = new JsonResult
                {
                    Data = new { Message = "Your session has died a terrible and gruesome death" },
                    JsonRequestBehavior = JsonRequestBehavior.AllowGet
                };
                filterContext.HttpContext.Response.StatusCode = 401;
                filterContext.HttpContext.Response.StatusDescription = "Humans and robots must authenticate";
                filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;
            }
        }
        //base.HandleUnauthorizedRequest(filterContext);
    }
}

回答by Sebastián Rojas

I don't see what we have to modify the authentication mode or the authentication tag like the current answer says.

我没有看到我们必须像当前答案所说的那样修改身份验证模式或身份验证标签。

Following the idea of @TimothyLeeRussell (thanks by the way), I created a customized Authorize attribute (the problem with the one of @TimothyLeeRussell is that an exception is throw because he tries to change the filterContext.Result an that generates a HttpException, and removing that part, besides the filterContext.HttpContext.Response.StatusCode = 401, the response code was always 200 OK). So I finally resolved the problem by ending the response after the changes.

遵循@TimothyLeeRussell 的想法(顺便感谢),我创建了一个自定义的 Authorize 属性(@TimothyLeeRussell 之一的问题是抛出异常,因为他试图更改生成 HttpException 的 filterContext.Result 和删除那部分,除了 filterContext.HttpContext.Response.StatusCode = 401,响应代码总是 200 OK)。所以我最终通过在更改后结束响应来解决问题。

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class BetterAuthorize : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.Request.IsAjaxRequest())
        {
            //Set the response status code to 500
            filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
            filterContext.HttpContext.Response.StatusDescription = "Humans and robots must authenticate";
            filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;

            filterContext.HttpContext.Response.End();
        }
        else
            base.HandleUnauthorizedRequest(filterContext);
    }
}

回答by Jared

You could also use the Global.asax to interrupt this process with something like this:

您还可以使用 Global.asax 以如下方式中断此过程:

    protected void Application_PreSendRequestHeaders(object sender, EventArgs e) {
        if (Response.StatusCode == 401) {
            Response.Clear();
            Response.Redirect(Response.ApplyAppPathModifier("~/Login.aspx"));
            return;
        }
    }

回答by Troels Thomsen

You could choose to create a custom FilterAttributeimplementing the IAuthorizationFilterinterface.

您可以选择创建自定义FilterAttribute实现IAuthorizationFilter接口。

In this attribute you add logic to determine if the request are supposed to return JSON. If so, you can return an empty JSON result (or do whatever you like) given the user isn't signed in. For other responses you would just redirect the user as always.

在此属性中,您添加逻辑以确定请求是否应该返回 JSON。如果是这样,您可以在用户未登录的情况下返回一个空的 JSON 结果(或做任何您喜欢的事情)。对于其他响应,您只需像往常一样重定向用户。

Even better, you could just override the OnAuthorizationof the AuthorizeAttributeclass so you don't have to reinvent the wheel. Add the logic I mentioned above and intercept if the filterContext.Cancelis true (the filterContext.Resultwill be set to an instance of the HttpUnauthorizedResultclass.

更妙的是,你可以只覆盖OnAuthorization了的AuthorizeAttribute类,所以您不必推倒重来。添加我上面提到的逻辑,如果filterContext.Cancel为真则拦截(filterContext.Result将设置为HttpUnauthorizedResult类的实例。

Read more about "Filters in ASP.NET MVC CodePlex Preview 4"on Phil Haacks blog. It also applies to the latest preview.

在 Phil Haacks 博客上阅读有关“ASP.NET MVC CodePlex Preview 4 中的过滤器”的更多信息。它也适用于最新预览。

回答by valter.santos.matos

You can call this method inside your action,

你可以在你的动作中调用这个方法,

 HttpContext.Response.End();

Example

例子

public async Task<JsonResult> Return401()
{
    HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
    HttpContext.Response.End();
    return Json("Unauthorized", JsonRequestBehavior.AllowGet);
}

From MSDN: The End method causes the Web server to stop processing the script and return the current result. The remaining contents of the file are not processed.

来自MSDN: End 方法导致 Web 服务器停止处理脚本并返回当前结果。不处理文件的其余内容。