原文:401 vs 403
多年来,关于“未授权”的场景应该使用什么样的 HTTP 状态码的讨论从未停歇过——并且原始的 HTTP 1.1 规范并未明确指出 401 (未授权)和 403 (禁止)的区别。
但是,肯定有必要区分在请求中没有提供或者提供无效凭据以及提供有效凭据但是对于正要尝试的操作凭据中的“实体”却并未授权的情况。
这里有一些例子:
- 在过去不错的 ASP.NET FormsAuth (在 Katana 中已经被应用到全新的 cookie 中间件里)中——401 会被转成 302 重定向到登录页面。对于匿名请求来说是不错的——但是当用户已经经过认证,一个失败的授权(比如,使用 [Authorize(Role = "foo")])也会导致登录页面的显示——这就会很不直观。你更倾向于解决这样的错误或者展示一个错误页。
- 在 Web API 中,对于基于令牌的认证,你的客户端需要能够区分令牌是否过期还是缺少必要的域 (scope) 。“Bearer 令牌的使用”规范 (http://tools.ietf.org/html/rfc6750) 对于这有明确的说明。过期的或者有缺陷的令牌应该返回 401 ——缺少域应该返回 403 。
你可能已经听到过 HTTP 1.1 规范最近已经重写了。同样现在状态码的使用也更加明确:
401 (未授权) 状态码指示请求没有被应用因为对于目标资源缺少合法的认证凭据。服务器生成的 401 响应 必须 发送一个 WWW-Authenticate 报文头,其字段至少包含一个可应用于目标资源的质询。
服务器接收到合法的凭据但是并不足以获取访问权限应该使用 403 (禁止) 状态码进行响应。
但是不幸的是,ASP.NET MVC/Web API 的 [Authorize] 属性并没有采取这样的方式——它总是发出 401 。对于失败的授权这个逻辑是简单的:“如果用户是匿名的——发出 401 ,如果不是——发出 403” (现在我们的域授权助手已经发出 403 了——参见 这里 和 这里)。
也许我们会在 vNext 中修复它。