当初开发的时候,System.Web.Mvc.AuthorizeAttribute是正确的——早期版本的HTTP规范将状态码401用于“未经授权”和“未经身份验证”。
从最初的规范来看:
如果请求已经包括授权凭据,则401响应表示对这些凭据已拒绝授权。
事实上,你可以在这里看到混淆的地方——它在表示“身份验证”时使用了“授权”一词。然而,在日常实践中,当用户经过身份验证但未经授权时,返回403 Forbidden更有意义。用户不太可能有第二组凭据来获取访问权限——用户体验非常糟糕。
考虑大多数操作系统——当您尝试读取无权访问的文件时,您不会看到登录屏幕!
值得庆幸的是,HTTP规范已更新(2014年6月)以消除歧义。
从“超文本传输协议(HTTP/1.1):身份验证”(RFC 7235)中:
401(未经授权)状态码表示请求未被应用程序执行,因为它缺少目标资源的有效身份验证凭据。
从“超文本传输协议(HTTP/1.1):语义和内容”(RFC 7231)中:
403 Forbidden状态码表示服务器理解了请求,但拒绝授权。
有趣的是,在发布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);
}
}
}