Почему AuthorizeAttribute перенаправляет на страницу входа для сбоев проверки подлинности и авторизации?
In ASP.NET MVC, вы можете пометить метод контроллера с помощью AuthorizeAttribute, например:
[Authorize(Roles = "CanDeleteTags")]
public void Delete(string tagName)
{
// ...
}
это означает, что, если текущий вошедший в систему пользователь не находится в роли "CanDeleteTags", метод контроллера никогда не будет вызван.
к сожалению, для сбоев, AuthorizeAttribute возвращает HttpUnauthorizedResult, который всегда возвращает код состояния HTTP 401. Это вызывает перенаправление на страницу входа.
если пользователь не вошел в систему, это имеет смысл. Однако, если пользователь - это уже войти в систему, но не в нужной роли, это сбивает с толку, чтобы отправить их обратно на страницу входа.
кажется,AuthorizeAttribute результате проверки подлинности и авторизации.
это кажется немного оплошностью в ASP.NET MVC, или я что-то упустил?
мне пришлось готовить DemandRoleAttribute это разделяет два. Когда пользователь не проходит проверку подлинности, он возвращает HTTP 401, отправляя их на страницу входа. Когда пользователь вошел в систему, но не в требуемой роли, он создает . В настоящее время перенаправляет на страницу ошибки.
конечно, я не должен этого делать?
6 ответов:
когда он был впервые разработан, система.Сеть.Mvc.AuthorizeAttribute делал правильные вещи - более старые версии спецификации HTTP использовали код состояния 401 как для "несанкционированного", так и для "неавторизованного".
из исходной спецификации:
Если запрос уже включал учетные данные авторизации, то ответ 401 указывает, что авторизация была отклонена для этих учетных данных.
в самом деле, вы можете увидеть путаница тут же-он использует слово "авторизация", когда оно означает"аутентификация". Однако в повседневной практике имеет смысл возвращать 403 запрещенный, когда пользователь аутентифицирован, но не авторизован. Маловероятно, что у пользователя будет второй набор учетных данных, который даст им доступ - плохой пользовательский опыт вокруг.
рассмотрим большинство операционных систем - когда вы пытаетесь прочитать файл, у вас нет разрешения на доступ, вам не отображается экран входа в систему!
к счастью, спецификации HTTP были обновлены (июнь 2014), чтобы устранить двусмысленность.
из "Hyper Text Transport Protocol (HTTP / 1.1): Authentication" (RFC 7235):
код состояния 401 (несанкционированный) указывает, что запрос не был применен, поскольку ему не хватает действительных учетных данных проверки подлинности для целевого ресурса.
из "протокола передачи гипертекста (HTTP / 1.1): семантика и содержание" (RFC 7231):
код состояния 403 (запрещено) указывает, что сервер понял запрос, но отказывается авторизовать его.
интересно, в то время ASP.NET MVC 1 был выпущен поведение AuthorizeAttribute было правильным. Теперь поведение неверно-спецификация HTTP / 1.1 была исправлена.
вместо того, чтобы пытаться изменить ASP.NET ' s страница входа перенаправляет, это проще просто исправить проблему в источнике. Вы можете создать новый атрибут с тем же именем (
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); } } }
добавьте это в свой логин Page_Load функции:
// User was redirected here because of authorization section if (User.Identity != null && User.Identity.IsAuthenticated) Response.Redirect("Unauthorized.aspx");когда пользователь перенаправлен туда, но уже вошел в систему, он показывает несанкционированную страницу. Если они не вошли в систему, он проваливается и показывает страницу входа.
Я всегда думал, что это не имеет смысла. Если вы вошли в систему и пытаетесь перейти на страницу, для которой требуется роль, которой у вас нет, вы перенаправляетесь на экран входа в систему с просьбой войти с пользователем, у которого есть роль.
вы можете добавить логику на страницу входа, которая проверяет, прошел ли пользователь проверку подлинности. Вы можете добавить дружеское сообщение, которое объясняет, почему они снова были избиты.
к сожалению, вы имеете дело с поведением по умолчанию ASP.NET проверка подлинности с помощью форм. Существует обходной путь (я еще не пробовал) обсуждается здесь:
http://www.codeproject.com/KB/aspnet/Custon401Page.aspx
(Это не относится к MVC)
Я думаю, что в большинстве случаев лучшим решением является ограничение доступа к несанкционированным ресурсам до того, как пользователь попытается туда попасть. Удалив / посерев ссылку или кнопку, которая может их принять на эту несанкционированную страницу.
вероятно, было бы неплохо иметь дополнительный параметр в атрибуте, чтобы указать, куда перенаправлять несанкционированного пользователя. Но пока я смотрю на AuthorizeAttribute как на страховочную сетку.
попробуйте это в вашем обработчике Application_EndRequest вашего глобального.файл ascx
if (HttpContext.Current.Response.Status.StartsWith("302") && HttpContext.Current.Request.Url.ToString().Contains("/<restricted_path>/")) { HttpContext.Current.Response.ClearContent(); Response.Redirect("~/AccessDenied.aspx"); }
Если вы используете 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; } } } }
Comments