登录表单的正确HTTP状态码是什么?

38

我正在为一个应用程序实现身份验证,并且使用了“身份验证方法”的可插拔系统。这使我能够同时实现基于HTTP基本认证和基于HTML的认证方式。

使用HTTP基本/摘要认证,服务器将发送401 未经授权响应头。然而,根据HTTP / 1.1 RFC

响应必须包含一个包含适用于请求资源的挑战(第14.47节) 的 WWW-Authenticate 头字段。

由于我不知道任何“html”WWW-Authenticate头,因此使用带有HTML登录表单的401似乎不合适。这方面是否有任何替代方案? 我想以符合RESTful标准的方式设计我的应用程序。

对于基于HTML的登录表单,正确的HTTP状态码(和标头)是什么? 登录失败时的正确代码是什么?

注意:我对摘要认证不感兴趣。

4个回答

20

这个怎么样?

当请求登录页面(一个公共页面)时,你会得到你想要的东西,因此状态码为200:

GET /login -> 200

当请求一个需要HTTP级别认证(如基本HTTP、SSL证书等)的页面时,如果你没有发起此认证,应用程序必须告诉浏览器自己需要为你发起认证:

GET /secured -> 401 with WWW-Authenticate header

当身份验证是基于cookie的会话时,您已经有一个cookie(如果不是这种情况,在请求页面时将使用set-cookie标头获取cookie),但是此cookie并不表示您被允许访问/ secured uri。因此,如果尝试访问此uri,则应该会收到“403 forbidden”状态。然后,“登录”操作只不过是通过POST请求更改应用程序状态以使应用程序授予此cookie访问权限,因此...
使用错误凭据登录:
GET /secured -> 403 with HTML login form (with action="/login")
POST /login -> 403 with HTML login form, displaying errors

使用正确的凭据登录,但权限不足:

GET /secured -> 403 with HTML login form (with action="/login")
POST /login -> 403 with HTML page saying "I know you are John, but you can't get this page"

使用正确的凭据和足够的权限登录:

GET /secured -> 403 with HTML login form (with action="/login")
POST /login -> 302 (temporary redirection to /secured)
GET /secured -> 200

如果使用不存在的凭据登录,应该返回404还是401? - Vishal Jamdade
1
与“使用错误的凭据登录”相同:403(禁止)。最好不要暗示哪些登录是存在的,哪些不存在… - Charles-Édouard Coste

17

对于HTML,我认为应该用400进行响应。

这可能也适用于非HTML请求,因为据我了解,401更多地被设计为响应需要身份验证的内容请求,而不是响应身份验证请求。

HTML并不总是允许完全使用RESTful API,所以在某些情况下可以削减一些角落,但在这种特殊情况下,也许有更好的方法我没有看到。


1
直接响应登录表单(而不是重定向)肯定是一种选择,实际上可能更合理。 - igorw
这可能是最实用的解决方案,因为HTTP倾向于混淆身份验证和授权。 - Hunter Morris
1
401状态码表示身份验证和授权尝试失败,也可以用于登录失败。而403状态码则用于完全限制数据访问 - 不需要进行身份验证/授权。 - Gelmir
1
我不同意使用400,因为它是“错误请求”,明显表示请求格式不正确。我认为关键问题是浏览器应该做什么。特别是关于登录表单的交付方式,是重定向还是注入。现在我用jetty进行重定向,重定向到/login表单,然后登录POST转到/j_security_check,从那里将重新定向回最初被拒绝的页面(尽管没有原始请求参数)。 - Gunther Schadow

8
这是一个棘手的问题,主要是因为人们使用的最成熟的HTTP客户端是浏览器。根据RFC,WWW-Authenticate头可以包含任何内容。基本身份验证和摘要身份验证只是更多标准化的挑战/响应机制的两个示例。您可以简单地指定一个类似于html-form id=foo的挑战,并返回401以及一个HTML表单。此外,请注意从规范中回忆起,可以在同一个WWW-Authenticate头中指定多个挑战,但我没有测试过不同方案的浏览器的经验。

-5

@2016-02-17 更新

登录表单的HTTP状态应该是200 OK

错误的HTTP状态最好使用401未经授权。(名称可能会引起混淆,401是关于身份验证的。RFC7235

3.1. 401未经授权

401(未经授权)状态代码表示请求未被应用,因为它缺少目标资源的有效身份验证凭据。生成401响应的服务器必须发送一个包含至少一个适用于目标资源的挑战的WWW-Authenticate头字段(第4.1节)。

如果请求包括身份验证凭据,则401响应表示已拒绝对这些凭据的授权。用户代理可以使用新的或替换的Authorization头字段(第4.2节)重复请求。如果401响应包含与先前响应相同的挑战,并且用户代理已经尝试过至少一次身份验证,则用户代理应向用户呈现所包含的表示,因为它通常包含相关的诊断信息。

如果您想处理没有权限的情况,您可能需要使用403 Forbidden [RFC7231]。
HTTP 422用于WebDAV,但含义可能符合需求。(大多数情况下不建议使用)
有关更多信息,请参见下面Cássio Mazzochi Molin的评论。
@s2016-02-12 **更新** *(这是已接受答案的参考。)*

登录表单的HTTP状态应为200

错误的HTTP状态最好使用400

HTTP 422用于WebDAV,但含义可能符合需求。 HTTP 401用于授权。不适用于身份验证。


@2016-02-12 原始内容

HTTP 422 现在比400/401更好的选择。 HTTP 422是另一种选择。

因为它意味着服务器理解数据,但某些数据不正确。即它可以向客户端显示用户名/密码不正确。

11.2. 422无法处理的实体

422(无法处理的实体)状态代码表示服务器了解请求实体的内容类型(因此415(不支持的媒体类型)状态代码不合适),并且请求实体的语法正确(因此400(错误请求)状态代码不合适),但无法处理包含的指令。例如,如果XML请求正文包含格式良好(即语法正确),但语义上错误的XML指令,则可能会出现此错误条件。

RFC4918


1
在您进行投票之前,请查看以下两个链接,可能会改变您的想法:https://dev59.com/bmQo5IYBdhLWcg3wVuKP http://www.bennadel.com/blog/2434-http-status-codes-for-invalid-data-400-vs-422.htm - goodseller
从语法方面来看,您考虑得没错。然而从身份验证的角度来看,422状态码确实具有更好的意义。难道不是吗? - goodseller
401是关于授权,而不是认证。我正在实现一个认证API,并发现了不同的方法(包括这个):400 vs 401 vs 422。你真的说得很有道理,可以看出Seldaek为什么选择400。 - goodseller
401 是关于 身份验证(authentication) 的,而 403 则是关于 授权(authorization) 的。想要了解更多细节,请参考 RFC 7231403(Forbidden)的说明:_[...] 意味着服务器理解了请求但拒绝了授权。[...] 如果请求中提供了身份验证凭证,服务器则认为这些凭证不足以授予访问权限 [...]_ - cassiomolin
1
哦,这让我疯了!这个名字太混淆了。非常感谢您对它的深入理解,并慷慨地分享带有清晰参考的信息。 ;) - goodseller
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接