Как перехватить 401 из проверки подлинности форм в ASP.NET MVC?

Я хотел бы создать страницу 401, если у пользователя нет правильного разрешения.

Пользователь запрашивает URL-адрес и перенаправляется на страницу входа (я запрещаю анонимность в web.config). Пользователь регистрируется успешно и перенаправляется на исходный URL-адрес. Тем не менее, при проверке разрешения определяется, что у пользователя нет необходимого разрешения, поэтому я хотел бы сгенерировать 401. Но проверка подлинности по формам всегда обрабатывает 401 и перенаправляет пользователя на страницу входа.

Для меня это неверно. Пользователь уже аутентифицирован, пользователь просто не имеет правильной авторизации.

В других сценариях, например, в сценарии службы ajax или REST, я определенно не хочу страницу входа в систему - мне нужна страница 401.

До сих пор я пробовал настраиваемый фильтр Authorize для возврата ViewResult с 401, но не работал. Затем я попробовал обычный Action Filter, переопределяющий OnActionExecuting, который тоже не работал.

Что мне удалось сделать, это обработать событие в global.asax, PostRequestHandlerExecute и проверить разрешение, а затем выписать непосредственно ответ:

if (permissionDenied)
{
    Context.Response.StatusCode = 401;
    Context.Response.Clear();
    Context.Response.Write("Permission Denied");
    Context.Response.Flush();
    Context.Response.Close();
    return;
}

Это работает, но это не совсем то, что я хочу. Прежде всего, я даже не уверен, что это подходящее событие или место в этом процессе. Во-вторых, я хочу, чтобы страница 401 имела немного больше контента. Предпочтительно, это должна быть страница aspx с, возможно, той же главной страницей, что и остальная часть сайта. Таким образом, любой, кто просматривает сайт, может видеть, что разрешение отклонено, но с тем же внешним видом и т.д., Но пользователь ajax или службы получит соответствующий код состояния, чтобы действовать.

Любая идея, как это можно достичь? Я видел другие сообщения с похожими запросами, но не видел решения, которые я могу использовать.

И нет, я не хочу 403.

Ответы

Ответ 1

Я нашел работоспособное решение.

401 перенаправление с помощью FormsAuthenticationModule происходит во время EndRequest. Поскольку во время обработки событий модули вызывается перед global.asax, мы можем переопределить код состояния после того, как FormsAuthenticationModule имеет свои грязные руки в запросе.

В моем настраиваемом AuthorizationFilter я установил HttpContext.Items [ "PermissionDenied" ] в true, а затем в мой global.asax EndRequest, я переворачиваю код состояния от 200 до 401. Затем я Server.Transfer к своему пользовательскому представлению PermissionDenied.

Я бы предпочел, чтобы сам FormsAuthenticationModule был обновлен, чтобы справиться с этим сценарием, но я думаю, что это не слишком хаки, что я думаю, что смогу жить с ним.

Очевидно, вы можете изменить, как вы сигнализируете, что global.asax должен перевернуть код состояния. Я просто попытался установить код состояния на что-то вроде 511 и использовал это как условие, а не HttpContext.Items, и это сработало. Я догадываюсь, что до сих пор правильный код состояния выходит за дверь, движок ASP.NET не волнует.

Ответ 2

HttpContext.Current.Response.SuppressFormsAuthenticationRedirect = true;

Ответ 3

Я согласен, что поведение по умолчанию неверно, особенно учитывая запросы Ajax. Я надеюсь увидеть какое-то решение в MVCv3 (скрещенные пальцы).

Единственный способ, которым я это знаю, - удалить раздел "Аутентификация" в файле web.config, это то, что ASP.NET ищет для перенаправления несанкционированных запросов. Насколько мне известно, эту функцию нельзя отключить. Если у вас есть раздел аутентификации, вы будете перенаправлены на URL-адрес входа, если ASP.NET когда-либо встретит код состояния 401.

Но, удалив это, у вас есть другие проблемы. Если вы хотите, чтобы пользователь был перенаправлен на страницу входа в систему для неадлайновых запросов, вам нужно будет реализовать свой собственный AuthorizeAttribute и использовать пользовательские настройки, чтобы определить, куда перенаправить. Кроме того, что-либо еще в разделе "Аутентификация", вероятно, придется повторно выполнить и вы. Не очень практичное решение в сложных местах.

Я не сделал этого сам, я решил вернуться вместо 403. Это раздражает отсутствие верного HttpCode, но это лучше, чем любое другое решение, которое я нашел до сих пор.