Действие контроллера, которое возвращает частичное представление, вставляет страницу входа при неудачной авторизации - PullRequest
21 голосов
/ 16 ноября 2010

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

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

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

Спасибо.

Ответы [ 2 ]

33 голосов
/ 17 ноября 2010

Решение 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");
    };
});
3 голосов
/ 17 апреля 2012

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...