asp.net-mvc - 为什么AuthorizeAttribute认证授权失败会重定向到登录页面?

标签 asp.net-mvc authentication authorization

在 ASP.NET MVC 中,您可以使用 AuthorizeAttribute 标记 Controller 方法,如下所示:

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

这意味着,如果当前登录的用户不属于“CanDeleteTags”角色,则永远不会调用 Controller 方法。

不幸的是,对于失败,AuthorizeAttribute 返回 HttpUnauthorizedResult,它始终返回 HTTP 状态代码 401。这会导致重定向到登录页面。

如果用户未登录,这是完全有道理的。但是,如果用户已经登录,但不具有所需的角色,则将其发送回登录页面会很困惑。

似乎 AuthorizeAttribute 混淆了身份验证和授权。

这似乎是 ASP.NET MVC 中的一个疏忽,还是我遗漏了什么?

我必须编写一个将两者分开的DemandRoleAttribute。当用户未经身份验证时,它会返回 HTTP 401,将其发送到登录页面。当用户登录但不具有所需角色时,它会创建一个 NotAuthorizedResult。目前,这会重定向到错误页面。

我当然不必这样做吗?

最佳答案

首次开发时,System.Web.Mvc.AuthorizeAttribute 做了正确的事情 - HTTP 规范的旧版本使用状态代码 401 来表示“未经授权”和“未经身份验证”。

来自原始规范:

If the request already included Authorization credentials, then the 401 response indicates that authorization has been refused for those credentials.

事实上,您可以看到其中的困惑 - 它使用“授权”一词,而它的意思是“身份验证”。然而,在日常实践中,当用户经过身份验证但未经授权时,返回 403 Forbidden 更有意义。用户不太可能拥有第二组可以授予他们访问权限的凭据 - 到处都是糟糕的用户体验。

考虑大多数操作系统 - 当您尝试读取无权访问的文件时,不会显示登录屏幕!

值得庆幸的是,HTTP 规范已更新(2014 年 6 月)以消除歧义。

来自“超文本传输​​协议(protocol) (HTTP/1.1):身份验证”(RFC 7235):

The 401 (Unauthorized) status code indicates that the request has not been applied because it lacks valid authentication credentials for the target resource.

来自“超文本传输​​协议(protocol) (HTTP/1.1):语义和内容”(RFC 7231):

The 403 (Forbidden) status code indicates that the server understood the request but refuses to authorize it.

有趣的是,在 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);
        }
    }
}

关于asp.net-mvc - 为什么AuthorizeAttribute认证授权失败会重定向到登录页面?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/238437/

相关文章:

asp.net-mvc - 如何在 Razor 中设置数字编辑器的最小值、最大值和默认值

c# - 路由中带有 id 的 ASP.NET Core 表单

php - 自动聚焦于输入表单

permissions - JasperServer角色问题

model-view-controller - 为什么身份验证通常在 MVC 的 Controller 中?

php - REST API 授权和身份验证(网络 + 移动)

c# - Asp.net MVC 2 缓存

django - 使用 django python-social-auth 重定向后 session 值丢失

ruby-on-rails - CanCan ruby​​ on rails 错误

c# - 在 Html.ActionLink 中包含所有查询字符串参数