401 код ответа для запросов json с ASP.NET MVC


35

Как отключить стандартную обработку ASP.NET кода ответа 401 (перенаправление на страницу входа) для запросов AJAX/JSON?

Для веб-страниц все в порядке, но для AJAX мне нужно получить код ошибки 401 вместо хорошего 302/200 для страницы входа.

Update: Есть несколько решений от Phil Хаака, PM из ASP.NET MVC - http://haacked.com/archive/2011/10/04/prevent-forms-authentication-login-page-redirect-when-you-donrsquot-want.aspx

18

среда ASP.NET разработана таким образом, что он всегда будет перенаправлять пользователя, если HttpResponse.StatusCode установлен в 401, но только если <authentication /> раздел Web.config найден.

Удаление раздела аутентификации потребует от вас для реализации перенаправления на страницу входа в свой атрибут, но это не должно быть большой проблемой.

  0

Лучший способ реализовать свое собственное перенаправление - подкласс AuthorizeAttribute, а когда он не авторизован, установите результат в RedirectResult вместо HttpUnauthorizedResult. 07 янв. 102010-01-07 15:44:45

+2

Да, но в этом случае OP хотел бы отправить HTTP-код 401, но не перенаправлять (правильно работать с JSON). 08 янв. 102010-01-08 20:34:45

  0

Работает для меня - хотя я настроил параметр как <authentication mode = "None" /> вместо полного удаления атрибута. 15 июн. 132013-06-15 03:20:54

+3

Um - за исключением того, что я использую аутентификацию форм в контроллерах MVC, поэтому на самом деле это не работает для меня. Требуется 404 && Forms Authentication решение, а не либо ||. 18 июн. 132013-06-18 04:18:48

+1

Что такое исправление, если вы хотите использовать проверку подлинности на основе форм и иметь настраиваемое перенаправление 401? 29 авг. 132013-08-29 16:59:01

+2

@DevDave - см. Мой ответ. 29 авг. 132013-08-29 22:52:34


1

Вы можете выбрать, чтобы создать пользовательский FilterAttribute реализующий интерфейс IAuthorizationFilter.

В этом атрибуте вы добавляете логику, чтобы определить, должен ли запрос возвращать JSON. Если это так, вы можете вернуть пустой результат JSON (или сделать что угодно), если пользователь не подписан. Для других ответов вы просто перенаправляете пользователя, как всегда.

Еще лучше, вы можете просто переопределить OnAuthorization класса AuthorizeAttribute, поэтому вам не нужно изобретать велосипед. Добавьте логику я уже упоминал выше, и перехватывает если filterContext.Cancel верен (filterContext.Result будет установлен экземпляром HttpUnauthorizedResult класса.

Подробнее о "Filters in ASP.NET MVC CodePlex Preview 4" на Phil Haacks блоге. Это также относится и к последнему предпросмотру.

  0

Но я все еще не могу получить код статуса ответа 401 для запроса AJAX. Даже если я настроил ответ в фильтре авторизации. Поскольку инфраструктура ASP.NET, которая улавливает 401 ответ и перенаправляется на страницу входа, находится поверх ASP.NET MVC. Если учесть, что пользователь не зарегистрирован пустым результатом JSON, это не очень правильно ... 24 сен. 082008-09-24 15:04:09

  0

Я не понял точно, что вы имели в виду до сих пор. Я добавляю новый ответ, который поможет решить вашу проблему. 24 сен. 082008-09-24 22:24:04

+1

как вам удалось опубликовать два ответа? :) 30 авг. 132013-08-30 09:13:50


2

Вы также можете использовать Global.asax, чтобы прервать этот процесс что-то вроде этого:

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

Я сделал это, за исключением того, что я проверил 302 и X-Requested-With в ответе от @troethom выше. 09 сен. 102010-09-09 18:35:57


24

В классическом ASP.NET вы получите код ответа 401 HTTP при вызове WebMethod с Ajax. Я надеюсь, что они изменят его в будущих версиях 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; 
    } 
} 
  0

Это действительно хорошее решение стоп-зазора, если вам нужно что-то быстрое, что работает. В противном случае я попытался бы реализовать ответ @troethom. 07 янв. 102010-01-07 15:44:04


8

Я хотел как проверку подлинности с помощью форм и возвращать 401 для запросов Ajax, которые не проходят проверку подлинности.

В конце концов, я создал специальный атрибут 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); 
    } 
} 
  0

Что делать, если я хочу использовать стандартные формы, разрешает переадресацию, когда пользователь не вошел в систему, но также вызывает пользовательские переадресации 401, когда пользователь не имеет соответствующего разрешения, каких-либо идей? 30 авг. 132013-08-30 11:41:59

  0

Вы получите нормальные формы переадресации на методы, которые не имеют этого AuthorizeAttribute. Вы также можете просто расширить этот атрибут, предоставив предложение «else» if (! FilterContext.IsAuthenticated), в котором вы должны проверить разрешения, а затем настроить перенаправление самостоятельно. 30 авг. 132013-08-30 18:42:13


2

Я не вижу, что мы должны изменить режим аутентификации или тег аутентификации, как говорит текущий ответ.

Следуя идее @TimothyLeeRussell (спасибо, кстати), я создал настраиваемый атрибут Authorize (проблема с одним из @TimothyLeeRussell заключается в том, что исключение выбрано потому, что он пытается изменить filterContext.Result a, который генерирует исключение HttpException и удаление этой части, кроме фильтраContext.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); 
    } 
} 
+1

свойство SuppressFormsAuthenticationRedirect было именно тем, что я искал. 14 июл. 152015-07-14 12:04:02


1

Вы можете вызвать этот метод внутри действия,

HttpContext.Response.End(); 

Пример

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

От MSDN: Метод End вызывает веб-сервер, чтобы остановить обработку сценария и возвращает ток результат. Оставшееся содержимое файла не обрабатывается.