如果用户试图访问要求用户登录的页面,则返回正确的http状态代码似乎存在很多混淆 .
那么基本上当我显示登录页面时会发送什么状态代码?
我很确定我们需要在 4xx
范围内使用状态代码 .
我'm not talking about HTTP authentication here, so that' s至少有一个我们不会使用的状态代码( 401 Unauthorized
) .
现在我们应该使用什么?答案(也在SO上)似乎有所不同:
根据答案here我们应该使用 403 Forbidden
.
但在状态代码的描述中是:
授权无效,请求不应重复 .
那看起来不像是正确的 . 由于授权WOULD帮助 .
所以让我们看看其他答案 . 答案here甚至根本不使用 4xx
范围,而是使用 302 Found
302 Found
状态代码的说明:
请求的资源暂时驻留在不同的URI下 . 由于重定向有时可能会被更改,因此客户端应该继续使用Request-URI来处理将来的请求 . 如果由Cache-Control或Expires头字段指示,则此响应仅可缓存 .
我认为这也不是我想要的 . 因为它不是位于不同URI下的请求资源 . 而是一个完全不同的资源(登录页面与经过身份验证的内容页面) .
所以我走了另一个解决方案令人惊讶地选择了另一个answer .
这个答案建议我们选择 400 Bad Request
.
此状态代码的说明是:
由于语法格式错误,服务器无法理解请求 . 客户端不应该在没有修改的情况下重复请求 .
我认为服务器理解请求很好,但只是在用户通过身份验证之前拒绝提供访问权限 .
另一个answer也说 403
响应是正确的,但它结束于:
如果这是一个面向公众的网站,你试图根据会话cookie拒绝访问[这就是我所做的],200具有适当的主体以指示需要登录或302临时重定向到登录页面是往往最好 .
所以 403
是正确的,但 200
或 302
是最好的 .
嘿!这就是我要找的:最好的解决方案 . 但最好不要和正确的一样吗?为什么它会是最好的?
感谢所有在这个问题上做到这一点的人:)
我知道我不应该太担心它 . 而且我认为这个问题更具假设性(不是真的,而是因为缺乏更好的词语而使用它) .
但这个问题现在困扰着我一段时间了 .
如果我会成为一名经理(他们总是会听到一些很酷的发音)我会说:但是,但是,但是,但是,宁静是重要的 . :-)
那么:在上述情况下使用状态代码是什么 the right way™
(如果有的话)?
tl;dr
当用户尝试访问需要登录的页面时,正确的http状态代码响应是什么?
8 回答
如果用户 has not provided any credentials 和您的API需要它们,请返回
401 - Unauthorized
. 这将挑战客户这样做 . 关于这种特殊情况的争论通常很少 .如果用户提供了有效的凭据,但他们是 insufficient 来访问所请求的资源(可能是凭证是针对免费增值帐户但所请求的资源仅适用于您的付费用户),您可以选择一些选项来解决这些问题 . HTTP代码定义:
返回
403 - Forbidden
. 这更具描述性,通常被理解为,"the supplied credentials were valid but still were not enough to grant access"返回
401 - Unauthorized
. 如果您对安全性感到偏执,您可能不希望将额外信息返回给客户端,如上面(1)中返回的那样返回
401
或403
,但在响应正文中提供有用信息,描述拒绝访问的原因 . 同样,这些信息可能比您希望提供的信息更多,以防它在某种程度上帮助攻击者 .就个人而言,我总是使用#1作为已通过有效凭据但与其关联的帐户无法访问所请求资源的情况 .
反过来,你要求“最好的”,“正确的方式”和“正确的”,这使得回答这个问题变得困难,因为这些标准不一定是可以互换的,事实上可能是冲突 - 特别是在涉及RESTfulness的地方 .
“最佳”答案取决于您的申请 . 您是否正在构建基于纯旧浏览器(POBB)的Web应用程序?您是在构建本机客户端(例如iOS或Android)并通过Web访问服务吗?您是否正在大量使用AJAX来推动网页更新?卷曲是预期的客户?
假设您正在构建传统的Web应用程序 . 让我们来看看Google是如何做到的(为简洁起见,输出切断):
Google首先将我们重定向到GMail的“真实”网址(使用302重定向) .
然后它将我们重定向到登录页面(使用302重定向) .
登录页面本身 is delivered with the 200 status code !
为什么这样?
从用户体验的角度来看,如果用户访问他们无法查看的页面,因为他们未经过身份验证,您希望将用户带到允许他们更正此页面的页面(通过登录) . 在这个例子中,登录页面是独立的,只是另一个页面(这就是为什么200是合适的) .
您可以抛出4XX页面,其中包含说明和登录页面的链接 . 事实上,这可能看起来更加RESTful . 但这是一种更糟糕的用户体验 .
好的,但有没有像403这样的东西有意义的情况?绝对 .
首先,请注意403在规范中没有明确定义 . 为了理解它应该如何使用,您需要了解它在现场的实现方式 .
403通常被诸如Apache和IIS之类的Web服务器用作当浏览器请求目录列表(以“/”结尾的URI)但是服务器禁用目录列表时返回的页面的状态代码 . 在这种情况下,403实际上是一个专门的404,除了让他/她知道出了什么问题之外,你可以为用户做很多事情 .
但是,这里's an example of a site that uses the 403 to both signal to the user that he/she doesn' t有足够的权限 and 要采取什么行动来纠正这种情况(详情请查看full response):
(顺便说一句,403也可以在基于Web的API中看到,比如Twitter的API;这里,403表示“请求已被理解,但它已被拒绝 . 随附的错误消息将解释原因 . 请求时使用此代码因更新限制而被拒绝 . “)
作为改进,让's assume, however, that you don' t想要用户登录页面,或强制用户按照指向登录页面的链接 . 相反,您希望在阻止用户看到的页面上显示登录表单 . 如果他们成功进行身份验证,他们会在页面重新加载时看到内容;如果他们失败了,他们会再次获得登录表单 . 他们从不导航到另一个URL .
在这种情况下,状态代码403很有意义,并且与401情况同源,但需要注意的是浏览器不会弹出一个要求用户进行身份验证的对话框 - 表单位于页面本身 .
这种身份验证方法并不常见,但它可能有意义,并且恕我直言,开发人员尝试实现的弹出式javascript模式到登录解决方案 .
它归结为这个问题,你想重定向还是不重定向?
Additional: 关于401状态代码的想法......
401状态代码 - 以及相关的基本/摘要式身份验证 - 有很多功能 . 它受到HTTP规范的支持,它得到了每个主流浏览器的支持,它本身并不是RESTful ......问题是,从用户体验的角度来看,它非常缺乏吸引力 . 有一个不可调整的,神秘的弹出式对话框,缺乏一个优雅的退出解决方案,等等 . 如果你(或你的利益相关者/客户)可以忍受这些问题(一个大的if),那么它可能有资格作为“正确的“解决方案 .
同意 . REST只是一种风格,而不是严格的协议 . 许多公共Web服务偏离了这种风格 . 您可以构建您的服务以返回您想要的任何内容 . 只需确保您的客户知道预期返回代码的方式 .
就个人而言,我一直使用401(未经授权)来指示未经身份验证的用户请求了需要登录的资源 . 然后,我要求客户端应用程序引导用户登录 .
我使用400(错误请求)来响应具有无效凭据的登录尝试 .
HTTP 302(移动)似乎更适合客户端是浏览器的Web应用程序 . 浏览器通常遵循响应中的重定向地址 . 这对于引导用户登录页面非常有用 .
错误 . 401是超文本传输协议(RFC 2616 Fielding,等人)的一部分,但不限于HTTP认证 . 此外,它是唯一的状态代码,表明请求需要用户身份验证 .
可以使用302和200代码,并且在某些情况下更容易实现,但不是全部 . 如果你想遵守规范,401是唯一正确的答案 .
而403确实是最错误的代码返回 . 正如你所说的......
因此,这显然不适合表明授权是一种选择 .
我会坚持标准: 401 Unauthorized
UPDATE
要添加更多信息,解除与......相关的混乱
如果你认为这会阻止你使用401,你必须记住还有更多:
这“表示身份验证方案”意味着您可以选择加入其他身份验证方案!
HTTP协议(RFC 2616)为访问身份验证方案定义了一个简单的框架,但您不必使用THAT框架 .
换句话说:你不会受到通常的WWW-Auth的束缚 . 您只需指出您的webapp如何进行授权,并在 Headers 中提供相应的数据,这就是全部 . 根据规格,使用401,您可以选择自己的授权毒药!这就是您的“webapp”可以执行您希望它在401标头和授权实现时执行的操作 .
不要让规格混淆你,认为你必须使用通常的HTTP身份验证方案 . 你没有!规范真正实施的唯一内容:您只需要/必须识别您的webapp的身份验证方案并传递相关参数,以使请求方能够启动潜在的授权尝试 .
如果您仍然不确定,我可以将所有这些都放在一个简单但可以理解的视角中:假设您明天将发明一个新的授权方案,那么规范也允许您使用它 . 如果规范限制了这种较新的授权技术实现的实现,那些规范将在很久以前被修改过 . 规范定义了标准,但它们并没有真正限制大量潜在的实现 .
您的“TL; DR”与“TL”版本不匹配 .
请求您需要授权请求的资源的正确响应是401 .
302不是正确的响应,因为事实上,资源在其他地方不可用 . 原始网址是正确的,客户端根本没有权利 . 如果你按照重定向,你实际上并没有得到你想要的东西 . 您将被放入与资源无关的特定工作流程中 .
403不正确 . 403是“无法从这里到达”的错误 . 你根本看不出来,我不在乎你是谁 . 有人认为403和404是相似的 . 区别仅在于403,服务器说“是的,我有它,但你不能”,而404则说“我对你所谈论的内容一无所知” . 安全人士认为404更“安全” . 为什么告诉他们他们不需要知道的事情 .
您遇到的问题与REST或HTTP无关 . 您的问题是尝试在客户端和服务器之间 Build 一些状态关系,最后通过一些cookie表现出来 . 整个资源 - > 302 - >登录页面都是关于使用被称为Web浏览器的黑客的用户体验,它恰好是库存形式,糟糕的HTTP客户端和糟糕的REST参与者 .
HTTP具有授权机制 . 授权标头 . 在通用浏览器中,围绕它的用户体验非常糟糕 . 所以没有人使用它 .
所以没有正确的HTTP响应(好吧有401,但是没有/不能使用它) . 没有正确的REST响应,因为REST通常依赖于底层协议(在这种情况下是HTTP,但我们已经解决了这个问题) .
所以 . 302 - > 200为登录页面是她写的 . 这就是你得到的 . 如果您没有使用浏览器,或者通过XHR或其他一些自定义客户端完成所有操作,那么这不是问题 . 您只需使用Authorization标头,遵循HTTP协议,并利用DIGEST或AWS使用的方案,并完成 . 然后,您可以使用适当的标准来回答这些问题 .
正如您所指出的那样,
403 Forbidden
明确定义了短语“授权无效”,但值得注意的是,作者几乎肯定在这里指的是HTTP授权(由于您的站点使用不同的授权方案,这确实无济于事) . 实际上,鉴于状态代码是向用户代理而不是用户发出的信号,这样的代码将是正确的,因为代理尝试提供的任何授权都不会进一步帮助进行所需的授权过程(c.f.401 Unauthorized
) .但是,如果从字面上理解
403 Forbidden
的定义并认为它仍然不合适,或许409 Conflict
可能适用?如RFC 2616 §10.4.10中所定义:确实存在与资源的当前状态冲突:资源处于"locked"状态,并且此类冲突只能通过用户提供其凭据并重新提交请求来实现 . 正文将包括“足够的信息以供用户识别冲突的来源" (it will state that they are not logged-in) and indeed will also include "足够的信息以供用户或用户代理解决问题”(即登录表单) .
Your Answer:
401 Unauthorized
特别是如果您不关心或不会将人员重定向到登录页面-要么-
302 Found
暗示有资源,但他们需要提供退还给它的凭据 . 只有在您使用重定向并确保在正文中提供适当的信息时才这样做响应 .Other Suggestions:
401 Unauthorized
通常用于处理身份验证后用户无权访问的资源 .403 Forbidden
在诚实中对我来说有点模糊 . 当我从文件系统级别锁定资源时,我使用它,就像你的帖子所说的那样,"authorization does not help" .400 Bad Request
不合适,因为需要登录并不代表格式错误的语法 .我相信401是从授权失败返回的正确状态代码 . 参考RFC 2616 section-14.8它显示“希望通过服务器验证自身的用户代理 - 通常,但不一定,在收到 401 响应后”