Подтвердить что ты не робот

Как вы обрабатываете запросы ajax, когда пользователь не аутентифицирован?

Как вы обрабатываете запросы ajax, когда пользователь не аутентифицирован?

Кто-то входит на страницу, оставляет место на час, возвращает, добавляет комментарий на странице, которая идет через huhu ajax, используя jQuery ($.post). Поскольку он не аутентифицирован, метод возвращает результат RedirectToRoute (перенаправляется на страницу входа). Что ты делаешь с этим? Как вы обрабатываете его на стороне клиента и как вы обрабатываете его в контроллере?

4b9b3361

Ответ 1

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);
    }
}

OLD ANSWER:

В то время как мне нравятся идеи, опубликованные в других ответах (о которых я имел в виду ранее), мне нужны образцы кода. Вот они:

Измененный атрибут Authorize:

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 переопределяется, поэтому при использовании Ajax он возвращает Http403Result. 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 (поэтому перенаправление на страницу входа выполняется после неудачной авторизации).

Что вы думаете об этом?

Ответ 2

Идея, с которой я столкнулся, когда коллега спросила о том, как с ней справиться, - это сделать атрибут AuthorizeAjax. Он может опросить и проверить, что Request.IsAjaxRequest() и, если запрос не аутентифицирован, возвращает конкретный объект ошибки JSON. Возможно, вы могли бы просто переопределить атрибут AuthorizeAttribute по умолчанию и вызвать его вызов, если это не несанкционированный запрос AJAX, поэтому вам не нужно беспокоиться о том, следует ли отмечать действия контроллера с помощью [Авторизовать] или [AuthorizeAjax].

На стороне клиента все ваши страницы должны быть оборудованы для обработки возвращенной ошибки, но эта логика может быть разделена.

Ответ 3

Я бы предложил создать свой собственный AuthorizeAttribute, и если запрос является запросом Ajax, бросьте HttpException (401/403). А также переключитесь на использование jQuery Ajax Method.

Предполагая, что вы внедрили страницы ошибок и вернули правильный код состояния, обратный вызов error будет выполнен вместо обратного вызова success. Это произойдет из-за кода ответа.

Ответ 4

Самое простое и чистое решение, которое я нашел для этого, - зарегистрировать обратный вызов с событием 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), но в большинстве случаев, когда отладка отсутствует, пользователь никогда их не увидит.

Если вы не хотите использовать встроенный заголовок, я уверен, что вы можете легко добавить пользовательский и следовать одному шаблону.

Ответ 5

Вот решение, которое я использую. Это мертво просто, если немного грубой силы. Мне нравится, потому что я ленив, и я не хочу думать о специальных атрибутах методов действий, и я не хочу писать обработчики ошибок ajax, если мне не нужно (хотя нет причин, по которым клиент script cann 't определить код статуса 403 и сделать что-то удобное для пользователя).

Помещая это в Global.axax, обнаруживает любой неаутентифицированный запрос ajax и просто возвращает 403 без содержимого. Это предотвращает перенаправление неавторизованных вызовов ajax в форму входа, когда используется проверка подлинности форм.

 protected void Application_AuthenticateRequest(object sender, EventArgs e)
    {
        // Prevent Ajax requests from being returned the login form when not authenticated
        // (eg. after authentication timeout).
        if ((Request.Headers["X-Requested-With"] != null && Request.Headers["X-Requested-With"] == "XMLHttpRequest")
            ||
            (Request["X-Requested-With"] != null && Request["X-Requested-With"] == "XMLHttpRequest"))
        {
            if (!Request.IsAuthenticated)
            {
                Response.Clear();
                Response.StatusCode = 403;
                Response.Flush();
                Response.End();
            }
        }
    }

Ответ 6

Вы можете обнаружить запрос ajax и отправить 401, а на стороне клиента вы можете даже показать диалоговое окно ajax с приглашением входа в систему, после чего вы сможете "продолжить" неудачный запрос ajax и заставить приложение работать, и пользователь чувствует, что тайм-аут сеанса никогда не будет получилось. Подробнее см. этот ответ.