Как отключить стандартную обработку кода ответа 401 в ASP.NET (перенаправление на страницу входа) для запросов AJAX / JSON?
Для веб-страниц это нормально, но для AJAX мне нужно получить правильный код ошибки 401 вместо красивого 302/200 для страницы входа.
Обновлять: Есть несколько решений от Фила Хаака, премьер-министра ASP.NET MVC - http://haacked.com/archive/2011/10/04/prevent-forms-authentication-login-page-redirect-when-you-donrsquot-want.aspx





Вы можете создать собственный FilterAttribute, реализующий интерфейс IAuthorizationFilter.
В этом атрибуте вы добавляете логику, чтобы определить, должен ли запрос возвращать JSON. Если это так, вы можете вернуть пустой результат JSON (или сделать что угодно), если пользователь не вошел в систему. Для других ответов вы просто перенаправляете пользователя, как всегда.
Более того, вы можете просто переопределить OnAuthorization класса AuthorizeAttribute, чтобы вам не пришлось изобретать велосипед. Добавьте логику, о которой я упоминал выше, и перехватите, если filterContext.Cancel истинно (filterContext.Result будет установлен в экземпляр класса HttpUnauthorizedResult.
Узнайте больше о «Фильтры в ASP.NET MVC CodePlex Preview 4» в блоге Фила Хакса. Это также относится к последнему превью.
До сих пор я не совсем понимал, что вы имели в виду. Я добавляю новый ответ, который решит вашу проблему.
Среда выполнения ASP.NET разработана таким образом, что она всегда перенаправляет пользователя, если для HttpResponse.StatusCode установлено значение 401, но только при обнаружении раздела <authentication /> файла Web.config.
Удаление раздела аутентификации потребует от вас реализации перенаправления на страницу входа в свой атрибут, но это не должно иметь большого значения.
Лучший способ реализовать собственное перенаправление - создать подкласс AuthorizeAttribute, а при отсутствии авторизации установить результат в RedirectResult вместо HttpUnauthorizedResult.
Да, но в этом случае OP хотел бы отправить HTTP-код 401, но не перенаправлять (для правильной работы с JSON).
У меня работает - хотя я настроил параметр как <authentication mode = "None" /> вместо того, чтобы полностью удалять атрибут.
Гм - за исключением того, что я использую проверку подлинности с помощью форм в контроллерах MVC, так что на самом деле это не работает для меня. Требуется решение для аутентификации 404 && Forms, а не либо ||.
Что делать, если вы хотите использовать аутентификацию с помощью форм и настроить перенаправление 401?
@DevDave - Смотри мой ответ.
Вы также можете использовать Global.asax, чтобы прервать этот процесс примерно так:
protected void Application_PreSendRequestHeaders(object sender, EventArgs e) {
if (Response.StatusCode == 401) {
Response.Clear();
Response.Redirect(Response.ApplyAppPathModifier("~/Login.aspx"));
return;
}
}
Я сделал это, за исключением того, что проверил 302 и X-Requested-With в ответе от @troethom выше.
В классическом ASP.NET вы получаете код ответа HTTP 401 при вызове 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;
}
}
Это действительно хорошее временное решение, если вам нужно что-то быстро работающее. В противном случае я бы попытался реализовать ответ @troethom.
Мне нужна была проверка подлинности с помощью форм и возвращение 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);
}
}
что, если я хочу использовать стандартные формы для авторизации перенаправления, когда пользователь не вошел в систему, а также для вызова пользовательских перенаправлений 401, когда у пользователя нет соответствующего разрешения, какие-либо идеи?
Вы получите обычное перенаправление форм для методов, у которых нет этого атрибута AuthorizeAttribute. Вы также можете просто расширить этот атрибут, указав предложение «else» в if (! FilterContext.IsAuthenticated), в котором вы будете проверять разрешения, а затем самостоятельно настраивать перенаправление.
Я не вижу, что нам нужно изменить режим аутентификации или тег аутентификации, как говорится в текущем ответе.
Следуя идее @TimothyLeeRussell (кстати, спасибо), я создал настраиваемый атрибут Authorize (проблема с атрибутом @TimothyLeeRussell заключается в том, что генерируется исключение, потому что он пытается изменить filterContext.Result an, который генерирует 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 было именно тем, что я искал.
Вы можете вызвать этот метод внутри своего действия,
HttpContext.Response.End();
Пример
public async Task<JsonResult> Return401()
{
HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
HttpContext.Response.End();
return Json("Unauthorized", JsonRequestBehavior.AllowGet);
}
Из MSDN: Метод End заставляет веб-сервер прекращать обработку сценария и возвращать текущий результат. Остальное содержимое файла не обрабатывается.
Но я все еще не могу получить код состояния ответа 401 для запроса AJAX. Даже если я настроил ответ в фильтре авторизации. Поскольку инфраструктура ASP.NET, которая перехватывает ответ 401 и перенаправляет на страницу входа, находится поверх ASP.NET MVC. Сообщать, что пользователь не вошел в журнал по пустому результату JSON, не очень правильно ...