Ответ 1
Решение 1, обратная реакция, указывающая на ошибку
Pro ASP.NET MVC 2 Framework предлагает одно решение для этого
Если запрос Ajax отказали в авторизации, затем обычно вы не хотите возвращать HTTP перенаправление на страницу входа, потому что ваш код на стороне клиента не ожидая этого и может что-то сделать нежелательные, например, инъекции всего страница входа в систему на какой странице пользователь включен. Вместо, вы хотите отправить более полезную сигнал на клиентский код, возможно, в формате JSON, чтобы объяснить что запрос не был санкционирован. Вы можете реализовать это следующим образом:
public class EnhancedAuthorizeAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext context)
{
if (context.HttpContext.Request.IsAjaxRequest()) {
UrlHelper urlHelper = new UrlHelper(context.RequestContext);
context.Result = new JsonResult {
Data = new {
Error = "NotAuthorized",
LogOnUrl = urlHelper.Action("LogOn", "Account")
},
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
else
base.HandleUnauthorizedRequest(context);
}
}
Затем вы вернете объект JSON из контроллера {'Error': 'NotAuthorized', 'LogonUrl': '...'}
, который затем можно использовать для перенаправления пользователя.
И альтернативный ответ, если вы ожидаете HTML, может состоять в том, чтобы вернуть обычную строку, например NotAuthorized:<your_url>
, и проверить, соответствует ли ответ этому шаблону.
Решение 2, код возврата и обработки 401 Unautorized
Поскольку это нужно проверять при каждом обратном вызове ajax-запроса success
, это становится довольно утомительным. Было бы неплохо уловить этот случай во всем мире. Лучшим решением было бы вернуть код состояния 401 Unauthorized
с сервера и использовать jQuery .ajaxError
, чтобы поймать его, но это проблематично на IIS/ASP.NET, поскольку он смертельно настроен перенаправить вас на страницу входа, если ответ имеет этот код состояния. Пока тег <authentication>
присутствует в web.config
, это перенаправление произойдет [1], если вы ничего не сделаете он.
Так что сделай что-нибудь об этом. Этот неудобный способ показался приятным. В вашем файле global.asax.cs
protected void Application_EndRequest()
{
if (Context.Response.StatusCode == 302 && Context.Request.RequestContext.HttpContext.Request.IsAjaxRequest())
{
Context.Response.Clear();
Context.Response.StatusCode = 401;
}
}
(Мне бы хотелось услышать это, если кто-нибудь знает какие-либо лучшие методы для возврата кода состояния 401
.)
Таким образом, вы предотвращаете поведение по умолчанию для перенаправления на страницу входа в систему, когда запрос является запросом ajax. Поэтому вы можете использовать значение по умолчанию AuthorizeAttribute
как есть, так как Application_EndRequest
заботится обо всем остальном.
Теперь в коде jQuery мы будем использовать функцию .ajaxError
, чтобы поймать ошибку. Это глобальный обработчик событий ajax, то есть он будет перехватывать каждую ошибку, вызванную любым вызовом ajax. Он может быть прикреплен к любому элементу - в моем примере, который я только что выбрал body
, он всегда присутствует
$("body").ajaxError(function(event, XMLHttpRequest, ajaxOptions, thrownError) {
if (XMLHttpRequest.status == 401) {
alert("unauthorized");
}
});
Таким образом, вы получаете логику перенаправления, централизованную в одном месте, вместо того, чтобы проверять ее на каждом проклятом ajax-запросе.
Решение 3, возврат пользовательского заголовка
Этот ответ предлагает альтернативное решение. Он использует один и тот же вид глобального обработчика событий, но пропускает взломанные биты. Он добавляет пользовательский заголовок к странице, если вы не аутентифицированы, а запрос является ajax-запросом и проверяет этот заголовок на каждом .ajaxComplete
. Обратите внимание, что метод, предоставленный в связанном ответе, небезопасен, так как он вернет исходное представление с возможно чувствительным контентом и полагается на javascript для перенаправления пользователя от него. С небольшим изменением это довольно удивительно, так как оно не требует каких-либо взломов, и логика может быть централизована для одной функции обратного вызова. Единственный недостаток, который я вижу, заключается в том, что он не отвечает с семантически правильным кодом состояния, поскольку он на самом деле не 200 OK
, потому что вы 401 Unauthorized
Мы можем испечь это в другой пользовательский EnhancedAuthorizationAttribute
public class EnhancedAuthorizeAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext context)
{
if (context.HttpContext.Request.IsAjaxRequest())
{
context.HttpContext.Response.AddHeader("REQUIRES_AUTH", "1");
context.Result = new EmptyResult();
}
else
{
base.HandleUnauthorizedRequest(context);
}
}
}
}
Теперь, каждый раз, когда запрос ajax завершается, вы проверяете этот заголовок:
$('body').ajaxComplete(function(event,request,settings){
if (request.getResponseHeader('REQUIRES_AUTH') === '1'){
alert("unauthorized");
};
});