Вопрос:

Почему AuthorizeAttribute перенаправляет на страницу входа в систему при сбое аутентификации и авторизации?

asp.net-mvc authentication authorization

86849 просмотра

7 ответа

58863 Репутация автора

В ASP.NET MVC вы можете пометить метод контроллера AuthorizeAttributeследующим образом:

[Authorize(Roles = "CanDeleteTags")]
public void Delete(string tagName)
{
    // ...
}

Это означает, что, если текущий зарегистрированный пользователь не находится в роли «CanDeleteTags», метод контроллера никогда не будет вызван.

К сожалению, для сбоев AuthorizeAttributeвозвращается HttpUnauthorizedResult, который всегда возвращает код состояния HTTP 401. Это вызывает перенаправление на страницу входа.

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

Похоже, что AuthorizeAttributeобъединяет аутентификацию и авторизацию.

Это похоже на упущение в ASP.NET MVC, или я что-то упустил?

Я должен был приготовить что-то, DemandRoleAttributeчто разделяет их. Когда пользователь не аутентифицирован, он возвращает HTTP 401, отправляя его на страницу входа. Когда пользователь вошел в систему, но не в требуемой роли, он создает NotAuthorizedResultвместо этого. В настоящее время это перенаправляет на страницу ошибки.

Конечно, я не должен был этого делать?

Автор: Roger Lipscombe Источник Размещён: 26.10.2008 06:51

Ответы (7)


4 плюса

22671 Репутация автора

К сожалению, вы имеете дело с поведением по умолчанию проверки подлинности форм ASP.NET. Здесь есть обходной путь (я не пробовал):

http://www.codeproject.com/KB/aspnet/Custon401Page.aspx

(Это не специфично для MVC)

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

Вероятно, было бы неплохо иметь дополнительный параметр в атрибуте, чтобы указать, куда перенаправлять неавторизованного пользователя. Но пока я смотрю на AuthorizeAttribute как на сеть безопасности.

Автор: Keltex Размещён: 26.10.2008 10:02

4 плюса

1363 Репутация автора

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

Вы можете добавить логику на страницу входа, которая проверяет, прошел ли пользователь аутентификацию. Вы можете добавить дружеское сообщение, которое объясняет, почему они снова были обмануты.

Автор: Rob Размещён: 27.10.2008 04:28

24 плюса

5020 Репутация автора

Добавьте это к вашей функции Login Page_Load:

// User was redirected here because of authorization section
if (User.Identity != null && User.Identity.IsAuthenticated)
    Response.Redirect("Unauthorized.aspx");

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

Автор: Alan Jackson Размещён: 01.04.2009 01:29

299 плюса

4928 Репутация автора

Решение

Когда он был впервые разработан, System.Web.Mvc.AuthorizeAttribute действовал правильно - более старые версии спецификации HTTP использовали код состояния 401 как для «неавторизованного», так и «неаутентифицированного».

Из оригинальной спецификации:

Если в запрос уже включены учетные данные авторизации, то ответ 401 указывает, что в авторизации было отказано для этих учетных данных.

На самом деле, вы можете увидеть путаницу прямо здесь - она ​​использует слово «авторизация», когда оно означает «аутентификация». Однако в повседневной практике имеет смысл возвращать 403 Запрещено, когда пользователь аутентифицирован, но не авторизован. Маловероятно, что у пользователя будет второй набор учетных данных, который предоставит ему доступ - плохой пользовательский опыт со всех сторон.

Рассмотрим большинство операционных систем - когда вы пытаетесь прочитать файл, к которому у вас нет прав доступа, вам не показывается экран входа!

К счастью, спецификации HTTP были обновлены (июнь 2014 г.), чтобы устранить неоднозначность.

Из «Гипертекстового транспортного протокола (HTTP / 1.1): аутентификация» (RFC 7235):

Код состояния 401 (неавторизованный) указывает, что запрос не был применен, поскольку в нем отсутствуют действительные учетные данные аутентификации для целевого ресурса.

Из «Протокола передачи гипертекста (HTTP / 1.1): семантика и контент» (RFC 7231):

Код состояния 403 (Запрещено) указывает, что сервер понял запрос, но отказывается его авторизовать.

Интересно, что на момент выпуска ASP.NET MVC 1 поведение AuthorizeAttribute было правильным. Теперь поведение некорректно - спецификация HTTP / 1.1 была исправлена.

Вместо того, чтобы пытаться изменить перенаправления страницы входа в ASP.NET, проще просто устранить проблему у источника. Вы можете создать новый атрибут с таким же именем ( AuthorizeAttribute) в пространстве имен вашего сайта по умолчанию (это очень важно), тогда компилятор автоматически подберет его вместо стандартного MVC. Конечно, вы всегда можете дать атрибуту новое имя, если вы предпочитаете такой подход.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class AuthorizeAttribute : System.Web.Mvc.AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.Request.IsAuthenticated)
        {
            filterContext.Result = new System.Web.Mvc.HttpStatusCodeResult((int)System.Net.HttpStatusCode.Forbidden);
        }
        else
        {
            base.HandleUnauthorizedRequest(filterContext);
        }
    }
}
Автор: ShadowChaser Размещён: 30.04.2011 10:00

0 плюса

21 Репутация автора

Попробуйте это в вашем обработчике Application_EndRequest вашего файла Global.ascx

if (HttpContext.Current.Response.Status.StartsWith("302") && HttpContext.Current.Request.Url.ToString().Contains("/<restricted_path>/"))
{
    HttpContext.Current.Response.ClearContent();
    Response.Redirect("~/AccessDenied.aspx");
}
Автор: Kareem Cambridge Размещён: 08.01.2015 09:44

0 плюса

13986 Репутация автора

Если вы используете aspnetcore 2.0, используйте это:

using System;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace Core
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
    public class AuthorizeApiAttribute : Microsoft.AspNetCore.Authorization.AuthorizeAttribute, IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            var user = context.HttpContext.User;

            if (!user.Identity.IsAuthenticated)
            {
                context.Result = new UnauthorizedResult();
                return;
            }
        }
    }
}
Автор: Greg Gum Размещён: 14.02.2018 11:05

0 плюса

1982 Репутация автора

В моем случае проблема заключалась в том, что «спецификация HTTP использовала код состояния 401 как для« неавторизованного », так и« неавторизованного »». Как сказал ShadowChaser.

Это решение работает для меня:

if (User != null &&  User.Identity.IsAuthenticated && Response.StatusCode == 401)
{
    //Do whatever

    //In my case redirect to error page
    Response.RedirectToRoute("Default", new { controller = "Home", action = "ErrorUnauthorized" });
}
Автор: César León Размещён: 18.03.2019 06:38
Вопросы из категории :
32x32