Как Вы обрабатываете запросы ajax, когда пользователь не аутентифицируется?
Кто-то вводит страницу, оставляет комнату в течение часа, возвратов, добавляет комментарий к странице, которая идет throuh ajax использование jQuery ($.post
). Так как он не аутентифицируется, возврат метода результат RedirectToRoute (перенаправления к странице входа в систему). Что Вы делаете с ним? Как Вы обрабатываете его на стороне клиента и как Вы обрабатываете его в контроллере?
РЕДАКТИРОВАТЬ:
Я написал выше ответ давным-давно, и теперь я считаю, что отправка 403 - неправильный путь. 403 имеет немного другое значение, и его просто не следует использовать. Это исправленный атрибут с использованием 401. Он отличается только дополнительным context.HttpContext.Response.End ()
в Http401Result и другим кодом HTTP:
public class OptionalAuthorizeAttribute : AuthorizeAttribute
{
private class Http401Result : ActionResult
{
public override void ExecuteResult(ControllerContext context)
{
// Set the response code to 401.
context.HttpContext.Response.StatusCode = 401;
context.HttpContext.Response.Write(CTRes.AuthorizationLostPleaseLogOutAndLogInAgainToContinue);
context.HttpContext.Response.End();
}
}
private readonly bool _authorize;
public OptionalAuthorizeAttribute()
{
_authorize = true;
}
//OptionalAuthorize is turned on on base controller class, so it has to be turned off on some controller.
//That is why parameter is introduced.
public OptionalAuthorizeAttribute(bool authorize)
{
_authorize = authorize;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
//When authorize parameter is set to false, not authorization should be performed.
if (!_authorize)
return true;
var result = base.AuthorizeCore(httpContext);
return result;
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
{
//Ajax request doesn't return to login page, it just returns 401 error.
filterContext.Result = new Http401Result();
}
else
base.HandleUnauthorizedRequest(filterContext);
}
}
СТАРЫЙ ОТВЕТ:
Хотя мне нравятся идеи, опубликованные в другие ответы (о которых я имел представление ранее), мне нужны были образцы кода. Вот они:
Измененный атрибут авторизации:
public class OptionalAuthorizeAttribute : AuthorizeAttribute
{
private class Http403Result : ActionResult
{
public override void ExecuteResult(ControllerContext context)
{
// Set the response code to 403.
context.HttpContext.Response.StatusCode = 403;
context.HttpContext.Response.Write(CTRes.AuthorizationLostPleaseLogOutAndLogInAgainToContinue);
}
}
private readonly bool _authorize;
public OptionalAuthorizeAttribute()
{
_authorize = true;
}
//OptionalAuthorize is turned on on base controller class, so it has to be turned off on some controller.
//That is why parameter is introduced.
public OptionalAuthorizeAttribute(bool authorize)
{
_authorize = authorize;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
//When authorize parameter is set to false, not authorization should be performed.
if (!_authorize)
return true;
var result = base.AuthorizeCore(httpContext);
return result;
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
{
//Ajax request doesn't return to login page, it just returns 403 error.
filterContext.Result = new Http403Result();
}
else
base.HandleUnauthorizedRequest(filterContext);
}
}
HandleUnauthorizedRequest
переопределен, поэтому он возвращает Http403Result
при использовании Ajax. Http403Result
изменяет StatusCode на 403 и в ответ возвращает сообщение пользователю. В атрибуте есть некоторая дополнительная логика (параметр authorize
), потому что я включаю [Authorize]
в базовом контроллере и отключаю его на некоторых страницах.
Другой важной частью является глобальная обработка этого ответа на стороне клиента. Это то, что я поместил в Site.Master:
<script type="text/javascript">
$(document).ready(
function() {
$("body").ajaxError(
function(e,request) {
if (request.status == 403) {
alert(request.responseText);
window.location = '/Logout';
}
}
);
}
);
</script>
Я размещаю ГЛОБАЛЬНЫЙ обработчик ошибок ajax, и когда когда-либо $. Post
завершается с ошибкой 403, появляется ответное сообщение и пользователь перенаправляется для выхода. страница. Теперь мне не нужно обрабатывать ошибку в каждом $.post
запрос, потому что он обрабатывается глобально.
Почему 403, а не 401? 401 обрабатывается внутри MVC framework (поэтому перенаправление на страницу входа выполняется после неудачной авторизации).
Что вы думаете об этом?
Когда мой коллега спросил, как с этим справиться, я пришел к следующей идее - создать атрибут AuthorizeAjax. Он может опросить и проверить, что Request.IsAjaxRequest () и, если запрос не аутентифицирован, вернуть конкретный объект ошибки JSON. Возможно, вы можете просто переопределить атрибут AuthorizeAttribute по умолчанию и заставить его вызывать базу, если это не несанкционированный запрос AJAX, поэтому вам не нужно беспокоиться о том, помечать ли действия контроллера с помощью [Authorize] или [AuthorizeAjax].
На стороне клиента все ваши страницы должны быть оборудованы для работы с возвращенной ошибкой, но эта логика, вероятно, может использоваться совместно.
Я бы предложил создать свой собственный AuthorizeAttribute, и если запрос является запросом Ajax , выбросить исключение HttpException (401/403). А также переключитесь на использование метода Ajax в jQuery .
Предполагая, что вы реализовали страницы ошибок и они возвращают правильный код состояния, будет выполнен обратный вызов error
вместо обратного вызова success
. Это произойдет из-за кода ответа.
Самым простым и чистым решением, которое я нашел для этого, является регистрация обратного вызова с событием jQuery.ajaxSuccess () и проверка заголовка ответа «X-AspNetMvc-Version».
Каждый запрос jQuery Ajax в моем приложении обрабатывается Mvc, поэтому, если заголовок отсутствует, я знаю, что мой запрос был перенаправлен на страницу входа, и я просто перезагружаю страницу для перенаправления верхнего уровня:
$(document).ajaxSuccess(function(event, XMLHttpRequest, ajaxOptions) {
// if request returns non MVC page reload because this means the user
// session has expired
var mvcHeaderName = "X-AspNetMvc-Version";
var mvcHeaderValue = XMLHttpRequest.getResponseHeader(mvcHeaderName);
if (!mvcHeaderValue) {
location.reload();
}
});
Страница перезагрузка может вызвать некоторые ошибки Javascript (в зависимости от того, что вы делаете с ответом Ajax), но в большинстве случаев, когда отладка отключена, пользователь никогда их не увидит.
Если вы не хотите использовать встроенный заголовок, я уверен, что вы легко можете добавить собственный заголовок и следовать тому же шаблону.