使用ASP.NET MVC的json请求的401响应代码

时间:2008-09-23 20:42:19

标签: asp.net-mvc

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

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

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

7 个答案:

答案 0 :(得分:24)

在经典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;
    }
}

答案 1 :(得分:18)

开发ASP.NET运行时,以便在HttpResponse.StatusCode设置为401时始终重定向用户,但仅当找到Web.config的<authentication />部分时才会重定向。

删除身份验证部分将要求您实现重定向到属性中的登录页面,但这不应该是一个大问题。

答案 2 :(得分:9)

我想要两种Forms身份验证,并为未经过身份验证的Ajax请求返回401.

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

// web.config中

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

//控制器

[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);
    }
}

答案 3 :(得分:2)

你也可以使用Global.asax来中断这个过程:

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

答案 4 :(得分:2)

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

遵循@TimothyLeeRussell的想法(感谢方式),我创建了一个自定义的Authorize属性(@TimothyLeeRussell的问题是抛出一个异常,因为他试图更改filterContext.Result并生成一个除了filterContext.HttpContext.Response.StatusCode = 401之外,HttpException和删除该部分,响应代码始终为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);
    }
}

答案 5 :(得分:1)

您可以选择创建实施FilterAttribute界面的自定义IAuthorizationFilter

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

更好的是,您可以覆盖OnAuthorization类的AuthorizeAttribute,这样您就不必重新发明轮子。添加上面提到的逻辑并在filterContext.Cancel为真时拦截(filterContext.Result将设置为HttpUnauthorizedResult类的实例。

在Phil Haacks博客上阅读有关"Filters in ASP.NET MVC CodePlex Preview 4"的更多信息。它也适用于最新的预览。

答案 6 :(得分:1)

您可以在操作中调用此方法,

 HttpContext.Response.End();

实施例

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

From MSDN:End方法使Web服务器停止处理脚本并返回当前结果。不处理文件的剩余内容。