更正需要授权的资源的http状态代码

时间:2011-12-05 17:23:10

标签: rest http-status-codes

如果用户试图访问要求用户登录的页面,则返回正确的http状态代码时会出现很多混淆。

基本上,当我显示登录页面时,会发送什么状态代码?

我很确定我们需要使用4xx范围内的状态代码。

我不是在谈论HTTP身份验证,因此至少有一个我们不会使用的状态代码(401 Unauthorized)。

现在我们应该使用什么?答案(也在这里也是如此)似乎有所不同:

根据答案here,我们应该使用403 Forbidden

但在状态代码的描述中是:

  

授权无效,请求不应重复。

那看起来不合适。由于授权可以帮助。

所以让我们看看其他一些答案。答案here甚至根本不使用4xx范围,而是使用302 Found

302 Found状态代码的说明:

  

请求的资源暂时驻留在不同的URI下。由于重定向有时可能会被更改,因此客户端应该继续使用Request-URI来处理将来的请求。如果由Cache-Control或Expires标头字段指示,则此响应仅可缓存。

我认为这也不是我想要的。因为它不是位于不同URI下的请求资源。而是一个完全不同的资源(登录页面与经过身份验证的内容页面)。

所以我继续前进并用另一种解决方案令人惊讶地选择了另一个answer

这个答案建议我们选择400 Bad Request

此状态代码的说明是:

  

由于语法格式错误,服务器无法理解该请求。客户不应该在没有修改的情况下重复请求。

我认为服务器很好地理解了请求,但在用户通过身份验证之前拒绝提供访问权限。

另一个answer也表示403响应是正确的,但它的结尾是:

  

如果这是一个面向公众的网站,你试图根据会话cookie拒绝访问[这就是我所做的],200用适当的主体来表明需要登录或302临时重定向到登录页面通常是最好的。

所以403是正确的,但200302是最好的。

喂!这就是我要找的:最好的解决方案。但最好不要和正确的一样吗?为什么它会是最好的?

感谢所有在这个问题上做到这一点的人:)

我知道我不应该太担心它。而且我认为这个问题更具假设性(不是真的,而是因为缺乏更好的词语而使用它)。

但是这个问题现在困扰着我一段时间了。

如果我会成为一名经理(他们总是会听到一些很酷的发音),我会说:但是,但是,但是,但是,宁静很重要。 : - )

那么:在上述情况下使用状态代码the right way™是什么(如果有的话)?

TL;博士

当用户尝试访问需要登录的页面时,正确的http状态代码响应是什么?

8 个答案:

答案 0 :(得分:45)

如果用户未提供任何凭据且您的API需要这些凭据,请返回401 - Unauthorized。这将挑战客户这样做。关于这种特殊情况的争论通常很少。

如果用户提供了有效凭据,但他们 不足以访问所请求的资源(可能是凭据是免费增值帐户,但所请求的资源仅适用于您的付费用户),则您拥有考虑到一些HTTP代码定义的松散性,有几个选项:

  1. 返回403 - Forbidden。这是更具描述性的,通常被理解为,“提供的凭据有效,但仍然不足以授予访问权限”
  2. 返回401 - Unauthorized。如果您对安全性感到偏执,您可能不希望将额外信息反馈给客户端,如上面(1)中所返回的那样
  3. 返回401403,但在回复正文中提供有用信息,说明拒绝访问的原因。同样,这些信息可能比你想要提供的更多,以防它在某种程度上帮助攻击者。
  4. 就个人而言,我总是将#1用于已通过有效凭据的情况,但与其关联的帐户无权访问所请求的资源。

答案 1 :(得分:26)

反过来,你要求“最好的”,“正确的方式”和“正确的”,这使得回答这个问题变得困难,因为这些标准不一定是可以互换的,事实上可能是冲突 - 尤其是关注RESTful。

“最佳”答案取决于您的申请。您是否正在构建基于纯旧浏览器(POBB)的Web应用程序?您是在构建本机客户端(例如iOS或Android)并通过Web访问服务吗?您是否大量使用AJAX来推动网页更新?卷曲是预期的客户吗?

假设您正在构建传统的Web应用程序。让我们来看看谷歌是如何做到的(为了简洁起见,输出切断):

$ curl -v http://gmail.com/
< HTTP/1.1 301 Moved Permanently
< Location: http://mail.google.com/mail/
< Content-Type: text/html; charset=UTF-8
< Content-Length: 225
< ...

Google首先将我们重定向到GMail的“真实”网址(使用302重定向)。

$ curl -v http://mail.google.com/mail/
< HTTP/1.1 302 Moved Temporarily
< Location: https://accounts.google.com/ServiceLogin?service=mail&passive=true&rm=false&continue=http://mail.google.com/mail/&scc=1&ltmpl=default&ltmplcache=2
< Content-Type: text/html; charset=UTF-8
< Content-Length: 352
< ...

然后它将我们重定向到登录页面(使用302重定向)。

$ curl -v 'https://accounts.google.com/ServiceLogin?service=mail&passive=true&rm=false&continue=http://mail.google.com/mail/&scc=1&ltmpl=default&ltmplcache=2'
< HTTP/1.1 200 OK
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< ...

登录页面本身随附200状态代码

为什么这样?

从用户体验的角度来看,如果用户访问他们无法查看的页面,因为他们未经过身份验证,您希望将用户带到允许他们更正此页面的页面(通过登录)。在这个例子中,登录页面是独立的,只是另一个页面(这就是为什么200是合适的)。

您可以抛出4XX页面,其中包含说明和登录页面的链接。事实上,这可能似乎更加RESTful。但这是一种更糟糕的用户体验。

好的,但有没有像403这样的东西有意义的话?绝对

首先,请注意403在规范中没有明确定义。为了理解它应该如何使用,你需要看看它是如何在现场实现的。

403常用于Apache和IIS等Web服务器,作为浏览器请求目录列表(以“/”结尾的URI)但服务器禁用目录列表时返回的页面的状态代码。在这种情况下,403实际上是一个专门的404,除了让他/她知道出了什么问题之外,没有什么可以为用户做的。

但是,这是一个使用403向用户发出信号的网站示例,他/她没有足够的权限采取什么行动来纠正这种情况(查看结果full response了解详情):

curl -v http://www.w3.org/Protocols/rfc2616/
< HTTP/1.1 403 Forbidden
< Content-Type: text/html; charset=iso-8859-1
< Content-Length: 1564
< ...

(顺便说一下,403也可以在基于网络的API中看到,比如Twitter的API;这里,403表示“请求已被理解,但它已被拒绝。附带的错误消息将解释原因。此代码使用当由于更新限制而拒绝请求时。“)

但是,作为改进,我们假设您不希望将用户重定向到登录页面,或强制用户按照指向登录页面的链接。相反,您希望在页面上显示用户无法看到的登录表单。如果他们成功进行身份验证,他们会在页面重新加载时看到内容;如果他们失败了,他们会再次获得登录表单。他们从不导航到另一个网址。

在这种情况下,状态代码403很有意义,并且与401案例同源,但需要注意的是浏览器不会弹出一个要求用户进行身份验证的对话框 - 表单在页面本身。

这种身份验证方法并不常见,但它可能有意义,并且恕我直言的开发人员试图实现的弹出式javascript模式登录解决方案。

归结为这个问题,你想重定向还是不重定向?

其他:关于401状态代码的想法......

401状态代码 - 以及相关的基本/摘要式身份验证 - 有很多功能。它受到HTTP规范的支持,它得到了每个主流浏览器的支持,它本身并不是RESTful ......问题是,从用户体验的角度来看,它非常缺乏吸引力。有一个不可调整的,神秘的弹出式对话框,缺乏一个优雅的退出解决方案等等。如果你(或你的利益相关者/客户)可以忍受这些问题(一个大的if),那么它可能有资格作为“正确的“解决方案。

答案 2 :(得分:10)

同意。 REST只是一种风格,而不是严格的协议。许多公共Web服务偏离了这种风格。您可以构建您的服务以返回您想要的任何内容。只需确保您的客户知道预期返回代码的方式。

就个人而言,我一直使用401(未经授权)来指示未经身份验证的用户请求了需要登录的资源。然后,我要求客户端应用程序引导用户登录。

我使用400(错误请求)来响应使用无效凭据的登录尝试。

HTTP 302(已移动)似乎更适合客户端是浏览器的Web应用程序。浏览器通常遵循响应中的重定向地址。这对于引导用户登录页面非常有用。

答案 3 :(得分:8)

  

我这里不是谈论HTTP身份验证,因此我们不会使用至少1个状态代码(401 Unauthorized)。

错误。 401是超文本传输​​协议(RFC 2616 Fielding,等人)的一部分,但不限于HTTP认证。此外,它是唯一的状态代码,表明请求需要用户身份验证。

302&amp;可以使用200个代码 ,并且在某些方案中更容易实现,但不是全部。如果你想遵守规范,401是唯一正确的答案。

403确实是最错误的代码返回。正如你所说的那样......

  

授权无效,请求不应重复。

因此,这显然不适合表明授权是一种选择。

我会坚持标准: 401 Unauthorized

-

<强>更新

添加更多信息,解除与......相关的混乱。

  

响应必须包含WWW-Authenticate头字段(第14.47节),其中包含适用于所请求资源的质询。

如果你认为这会阻止你使用401,你必须记住还有更多:

  

“字段值至少包含一个挑战,指示适用于Request-URI的身份验证方案和参数。”

此“表示身份验证方案”表示您可以选择加入其他身份验证方案!

HTTP协议(RFC 2616)定义了一个用于访问身份验证方案的简单框架,但您无需使用该框架。

换句话说:你不会受到通常的WWW-Auth的束缚。你只需要指出你的webapp如何进行授权并在标题中提供相应的数据,这就是全部。根据规格,使用401,您可以选择自己的授权毒药!这就是您的“webapp”可以执行您希望它在401标头和授权实现时执行的操作。

不要让规格混淆你,认为你必须使用通常的HTTP身份验证方案。你没有!规范唯一真正强制执行的是:您只需要/必须识别您的webapp的身份验证方案并传递相关参数,以使请求方能够启动潜在的授权尝试。

如果您仍然不确定,我可以将所有这些放在一个简单但可以理解的视角中:假设您明天将发明一个新的授权方案,那么规范也允许您使用它。如果规范限制了这种较新的授权技术实现的实现,那些规范将在很久以前被修改。规范定义了标准,但它们并没有真正限制大量潜在的实现。

答案 4 :(得分:3)

您的“TL; DR”与“TL”版本不匹配。

请求您需要授权请求的资源的正确响应是401。

302不是正确的响应,因为事实上,资源在其他地方不可用。原始网址是正确的,客户端根本没有权利。如果你按照重定向,你实际上并没有得到你想要的东西。您将被放入一些与资源无关的临时工作流程。

403不正确。 403是“无法从这里到达”的错误。你根本看不出来,我不在乎你是谁。有人认为403和404是相似的。区别仅在于403,服务器说“是的,我有它,但你不能”,而404则说“我对你所谈论的内容一无所知”。安全人士会争辩说404更“安全”。为什么告诉他们他们不需要知道的事情。

您遇到的问题与REST或HTTP无关。您的问题是尝试在客户端和服务器之间建立一些状态关系,最后通过一些cookie表现出来。整个资源 - &gt; 302 - &gt;登录页面是关于使用被称为Web浏览器的黑客的用户体验,它恰好是库存形式,糟糕的HTTP客户端和糟糕的REST参与者。

HTTP具有授权机制。授权标头。在通用浏览器中,围绕它的用户体验非常糟糕。所以没有人使用它。

所以没有正确的HTTP响应(有,401,但不能/不能使用它)。没有正确的REST响应,因为REST通常依赖于底层协议(在这种情况下是HTTP,但我们已经解决了这个问题)。

因此。 302 - &gt;登录页面只有她写的200。这就是你得到的。如果您没有使用浏览器,或者通过XHR或其他一些自定义客户端完成所有操作,那么这不是问题。您只需使用Authorization标头,遵循HTTP协议,并利用DIGEST或AWS使用的方案,并完成。然后,您可以使用适当的标准来回答这些问题。

答案 5 :(得分:3)

正如您所指出的那样,403 Forbidden明确定义了短语“授权将无法帮助”,但值得注意的是,作者几乎肯定在这里指的是HTTP授权(由于您的网站使用不同的授权方案,这确实无济于事。实际上,鉴于状态代码是用户代理而不是用户的信号,这样的代码将是正确的,因为代理尝试提供的任何授权都不会通过所需的授权流程进一步协助(参见401 Unauthorized)。

但是,如果您从字面上理解403 Forbidden的定义并认为它仍然不合适,那么409 Conflict可能适用吗?如RFC 2616 §10.4.10中所定义:

   The request could not be completed due to a conflict with the current
   state of the resource. This code is only allowed in situations where
   it is expected that the user might be able to resolve the conflict
   and resubmit the request. The response body SHOULD include enough
   information for the user to recognize the source of the conflict.
   Ideally, the response entity would include enough information for the
   user or user agent to fix the problem; however, that might not be
   possible and is not required.

确实存在与资源的当前状态的冲突:资源处于“锁定”状态,并且这种冲突只能通过用户提供其凭证并重新提交请求来“解决”。正文将包含“足够的信息,以便用户识别冲突的来源”(它将声明他们没有登录),并且确实还包括“足够的信息用户或用户代理来解决问题“(即登录表单)。

答案 6 :(得分:0)

你的答案:

401 Unauthorized特别是如果您不关心或不会将人员重定向到登录页面

- 或 -

302 Found暗示有资源,但他们需要提供要返回给它的凭据。只有在您使用重定向并确保在响应正文中提供适当的信息时才执行此操作。


其他建议:

401 Unauthorized通常用于处理身份验证后用户无权访问的资源。

403 Forbidden在诚实中对我来说有点模糊。我在从文件系统级别锁定资源时使用它,就像你的帖子所说的那样,“授权没有帮助”。

400 Bad Request不合适,因为需要登录并不代表格式错误的语法。

答案 7 :(得分:0)

我相信401是从授权失败返回的正确状态代码。参考RFC 2616 section-14.8 它显示为“希望通过服务器验证自身的用户代理 - 通常但不一定,在收到 401 响应后”