如果用户尝试使用不正确的用户名/密码登录,但格式正确,应该返回什么 HTTP状态码?

这里也有一个类似的问题: 什么是一个合适的 HTTP状态码返回一个 REST API 服务验证失败?

上面的线程中的答案是: “例如,如果 URI 应该有一个 ISO-8601日期,而你发现它的格式不对或者指向2月31日,那么你将返回一个 HTTP 400。如果希望在实体主体中使用格式良好的 XML,但它无法进行解析,那么情况也是如此。”

但是,如果用户提交了格式正确的数据,会发生什么情况?我的意思是,用户提交了一个纯字母字符串/文本作为用户名和密码(这对我的应用程序是完全有效的)。唯一的问题是密码与用户名不匹配。在这种情况下,400将是不正确的,因为它是完全有效的语法和格式良好的。

一个401将是不正确的(正如建议在这里: 用户名或密码哪个 HTTP状态码不正确?) ,因为用户没有尝试访问任何页面,他只是试图登录和输入数据不匹配。

如果你回头看看我链接到的第一篇文章,第二个答案说422是正确的回复(在我看来是正确的) ,然而,我使用的是 Django Rest Framework,422不是状态码的一部分(一个状态码的列表,属于 DRF 的一部分,可以在这里找到: http://www.django-rest-framework.org/api-guide/status-codes/#client-error-4xx)

404看起来也不正确,因为数据被成功地接受而不是拒绝。

那么,应该使用的真正正确的反应是什么?

132171 次浏览

如果您严格使用 RFC 7235为 REST API 提供的 HTTP 身份验证框架,那么正确的 HTTP 代码实际上应该是401。来自 RFC:

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

如果请求中包含身份验证凭据,那么401响应将指示这些凭据的授权已被拒绝。用户代理可以使用新的或替换的 Authorization 头字段重复请求(第4.2节)。

RESTAPI 应该使用某种类型的 认证计划,以便向客户端返回有效的401响应。

RFC 7235的另一个相关章节,第4页:

在收到对被保护资源的请求时,忽略
证书、 包含无效的凭据(例如,错误的密码)
部分凭据(例如,当认证方案需要
多次往返) ,< strong > 原始服务器应该发送一个401 < br/> (未经授权)包含 WWW-Authenticate 头字段的响应 至少有一项(可能是新的)挑战适用于
请求的资源

更高级别的响应,比如为可视用户呈现登录页面(通过302从受保护的资源重定向) ,最好使用200状态代码(例如,按照@KernelDeimos 的回答)。由于登录页面是 一般来说自己的资源(例如 /login?redirect=original-resource) ,未经身份验证的用户仍然有权查看该页面,即使他们提供了不正确的用户名/密码。然后,将经过身份验证的用户重定向回资源,如果允许,此时将显示200,如果禁止用户查看资源,则显示403。

在可视化登录页面中,401可以发挥作用的领域是一个前端库,它利用使用 XHR 请求的 REST API,然后将来自 REST API 的401响应转发回登录页面上的一种有意义的格式。

2xx中使用适当的状态代码成功处理具有错误密码的登录请求。

在询问“正确的 HTTP状态码是什么”之前,重要的是要考虑这个问题: “登录的成功或失败是否应该反映在响应的 HTTP状态码中?”

在@sjagr 的回答中,突出显示了本节的第一部分。我将强调第二部分并解释原因:

如果请求中包含身份验证凭据,那么401响应指示这些凭据的授权已被拒绝

这指的是 Authorization头,而不是包含登录凭据的请求主体。遗憾的是,第一部分的措辞可能会被误解为引用包含登录信息的请求主体。这种模糊性可以通过考虑 关注点分离来解决; (https://en.wikipedia.org/wiki/Separation_of_concerns)服务器的响应头不应该依赖于两个有效请求体的差异,除非它导致内部服务器错误,否则数据传输和应用程序登录的关注开始相互渗透。

对于有效的登录请求,我将使用 HTTP 响应 2xx,其中客户端具有尝试登录的权限,该请求将通过指示成功或失败的响应成功处理。

我也喜欢@specas 在评论中表达的方式:

尝试在传输级状态代码中表示应用程序级错误是一个设计错误。

如果您尝试使用错误的密码登录到 Google 帐户,它将返回一个200响应,其中包含指示密码不正确的数据。因为这个原因,我只用了200。

最后,您使用的状态代码纯粹是一个语义问题,不会改变应用程序的功能。真正重要的是应用程序向用户显示正确的信息。

我认为造成混乱的原因是有两个实体需要验证。一个是客户端(前端应用程序)需要验证自己,即它被授权为用户发出登录请求,然后用户需要用他的用户名/密码验证自己。

状态代码应该只与发出请求的客户端相关,而不是与用户相关。

来自 https://developer.mozilla.org/en-US/docs/Web/HTTP/Status

HTTP 响应状态代码指示特定 HTTP 请求是否已成功完成。

200是正确的: 假设您有一个与后端对话的前端应用程序,适当的响应代码应该是200,如果密码匹配或不匹配,响应主体应该包含信息,但是这个结果对状态代码没有影响,因为请求本身已经被授权并成功解析。

401错了 : 例如,假设您的前端使用令牌进行身份验证,那么响应代码 401将意味着前端令牌无效,而不是该请求中用户的密码。

403是错误的 : 例如,假设您的前端使用令牌进行身份验证,那么响应代码 403将意味着令牌是有效的,但该令牌没有询问密码/用户名是否匹配的访问权限。