Решение 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
код состояния
Поскольку это необходимо проверять при каждом обратном вызове success
запроса ajax, это становится довольно утомительным.Было бы хорошо иметь возможность поймать этот случай во всем мире.Лучшим решением было бы вернуть код состояния 401 Unauthorized
с сервера и использовать .ajaxError
jQuery для его перехвата, но это проблематично в 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
Мы можем испечь это в другойcustom 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");
};
});