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

Действие контроллера, которое возвращает частичный вид, вставляет страницу входа в систему при сбое авторизации

У меня есть представление, которое загружает частичный вид из действия контроллера с помощью jQuery. Действие контроллера украшено атрибутом Authorize, и если пользователь отключился, когда это действие вызвано, чтобы перенаправить его на нужную страницу LogOn, страница LogOn будет вставлена ​​в представление, в котором частичное представление исчезло бы.

Существует еще одно сообщение здесь, в котором описывается решение с использованием jQuery, но, к сожалению, оно не содержит никаких образцов кода, которые мне нужны, потому что я не очень хорошо знаком с jQuery (и новым для веб-разработки), и мне нужно решить эту проблему, как только смогу.

Все, что я хочу сделать, это перенаправить пользователя на нужную страницу LogOn, которая звучит довольно прямо на меня, но пока это не похоже. Если jQuery - это способ пойти, может кто-то, пожалуйста, разместите образец кода, который действительно поможет мне.

Спасибо.

4b9b3361

Ответ 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");
    };
});

Ответ 2

Для второго решения Simen Echholt вы можете использовать

$.ajaxSetup({ global: true,
    statusCode: {
        401: function () {
            alert("unauthorized");
        }
    }
});

чтобы связать некоторую вашу функцию с кодом состояния 401