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

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

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

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

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

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

В classическом 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; } } 

Мне нужна была проверка подлинности с помощью форм и возврат 401 для Ajax-запросов, которые не были аутентифицированы.

В конце концов, я создал пользовательский атрибут AuthorizeAttribute и украсил методы controllerа. (Это на .Net 4.5)

//web.config

   

// controller

 [Authorize(Roles = "Administrator,User"), Response302to401] [AcceptVerbs("Get")] public async Task GetDocuments() { string requestUri = User.Identity.Name.ToLower() + "/document"; RequestKeyHttpClient, string> client = new RequestKeyHttpClient, string>(requestUri); var documents = await client.GetManyAsync>(); 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); } } 

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

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

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

Следуя идее @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); } } 

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

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

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

Подробнее о «Фильтры в ASP.NET MVC CodePlex Preview 4» в блоге Phil Haacks. Это также относится к последнему превью.

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

  HttpContext.Response.End(); 

пример

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

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

  • Как перенаправить указатель с другого controllerа?
  • Где разместить AutoMapper.CreateMaps?
  • Тип содержимого ASP.NET MVC и text / xml
  • Добавление фабрики controllerов в ASP MVC
  • Атрибуты HttpPost и HttpGet в MVC: зачем использовать HttpPost?
  • Как установить маршрут по умолчанию (в зону) в MVC
  • Как загрузить файл и сохранить его в Stream для дальнейшего просмотра с помощью C #?
  • Экспорт модели в DataTable
  • 403 - Forbidden: Отказано в доступе. ASP.Net MVC
  • Идентификатор ASP.NET - несколько наборов объектов для каждого типа не поддерживаются
  • Гиперссылки html с asp.net mvc
  • Давайте будем гением компьютера.