EDIT:
Я написал ответ выше, давным-давно, и теперь я считаю, что отправка 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>
Я помещаю GLOBAL ajax обработчик ошибок, и когда когда-либо $.post
завершается с ошибкой 403, выдается ответное сообщение, и пользователь перенаправляется на страницу выхода. Теперь мне не нужно обрабатывать ошибку в каждом $.post
запросе, потому что он обрабатывается глобально.
Почему 403, а не 401? 401 внутренне обрабатывается платформой MVC (поэтому перенаправление на страницу входа выполняется после неудачной авторизации).
Что вы думаете об этом?