【问题标题】:401 response code for json requests with ASP.NET MVC使用 ASP.NET MVC 的 json 请求的 401 响应代码
【发布时间】:2008-09-23 20:42:19
【问题描述】:

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

对于网页没问题,但对于 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

【问题讨论】:

    标签: asp.net-mvc


    【解决方案1】:

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

    【讨论】:

    • 如果您需要快速有效的解决方案,这是一个非常好的权宜之计。否则我会尝试实施@troethom 答案。
    【解决方案2】:

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

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

    【讨论】:

    • 实现自己的重定向的最佳方法是继承 AuthorizeAttribute,当未授权时,将结果设置为 RedirectResult 而不是 HttpUnauthorizedResult。
    • 是的,但在这种情况下,OP 想要发送 HTTP 代码 401,但不重定向(以便与 JSON 一起正常工作)。
    • 嗯 - 除了我在 MVC 控制器中使用表单身份验证,所以实际上这对我不起作用。需要 404 && 表单身份验证解决方案,而不是 ||。
    • 如果您想使用表单身份验证并进行自定义 401 重定向,解决办法是什么?
    • @DevDave - 查看我的回答。
    【解决方案3】:

    我想要表单身份验证并为未通过身份验证的 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);
    }
    

    //授权属性

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

    【讨论】:

    • 如果我想在用户未登录时使用标准表单授权重定向,并且在用户没有相关权限时调用自定义401重定向,有什么想法吗?
    • 您将在没有此 AuthorizeAttribute 的方法上获得正常形式的重定向。您也可以通过提供 if(!filterContext.IsAuthenticated) 的“else”子句来扩展此属性,您可以在其中检查权限,然后自己设置重定向。
    【解决方案4】:

    您也可以使用 Global.asax 来中断这个过程,如下所示:

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

    【讨论】:

    • 我这样做了,除了我在上面@troethom 的答案中检查了 302 和 X-Requested-With。
    【解决方案5】:

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

    按照@TimothyLeeRussell 的想法(顺便感谢一下),我创建了一个自定义的 Authorize 属性(@TimothyLeeRussell 的一个问题是抛出异常,因为他试图更改 filterContext.Result 并生成一个HttpException,并删除该部分,除了 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);
        }
    }
    

    【讨论】:

    • SuppressFormsAuthenticationRedirect 属性正是我想要的。
    【解决方案6】:

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

     HttpContext.Response.End();
    

    例子

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

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

    【讨论】:

      【解决方案7】:

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

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

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

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

      【讨论】:

      • 但我仍然无法获得 AJAX 请求的 401 响应状态代码。即使我在 Autorization 过滤器中设置了响应。由于捕获 401 响应并重定向到登录页面的 ASP.NET 基础结构位于 ASP.NET MVC 之上。让用户知道用户没有被空的 JSON 结果记录是不太正确的......
      • 直到现在我才完全理解你的想法。我正在添加一个可以解决您的问题的新答案。
      猜你喜欢
      • 2011-04-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-16
      • 1970-01-01
      • 2020-06-06
      • 1970-01-01
      相关资源
      最近更新 更多