RESTful 登录失败: 返回401或自定义响应

这是一个概念性的问题。

我有一个客户端(移动)应用程序,它需要支持针对 RESTful Web 服务的登录操作。因为 Web 服务是 RESTful 的,这相当于客户机从用户那里接受一个用户名/密码,用服务验证该用户名/密码,然后只需记住随后的所有请求发送该用户名/密码。

此 Web 服务中的所有其他响应都以 JSON 格式提供。

问题是,当我查询 Web 服务只是为了找出一个给定的用户名/密码是否有效时,Web 服务是否应该总是用 JSON 数据告诉我它的成功还是失败,或者它是否应该在良好凭证上返回 HTTP 200,在不良凭证上返回 HTTP 401。

我问这个问题的原因是,其他一些 RESTful 服务使用401作为坏凭据,即使您只是询问凭据是否有效。然而,我对401响应的理解是,它们代表了一种资源,如果没有有效的凭据,您就不应该访问这种资源。但是登录资源应该是任何人都可以访问的,因为登录资源的全部用途是告诉您您的凭证是否有效。

换句话说,在我看来,这样的请求:

myservice.com/this/is/a/user/action

如果提供了不良凭证,则应返回401。但是,如果提出以下请求:

myservice.com/are/these/credentials/valid

应该永远不会返回401,因为该特定的 URL (请求)是授权或没有有效的凭据。

不管怎样,我希望听到一些合理的意见。处理这个问题的标准方法是什么? 处理这个问题的标准方法在逻辑上是否合适?

112626 次浏览

首先,当发生登录失败时,401是正确的响应代码。

未经授权 类似于403禁用,但是特别适用于需要身份验证且身份验证失败或尚未提供身份验证时使用。响应必须包含一个 WWW-Authenticate 头字段,其中包含适用于请求资源的询问。

你对于 myservice.com/are/these/credentials/valid在你刚刚做检查时发回401的困惑,我认为是基于这样一个事实: 在 REST 中执行布尔请求通常由于 REST 的约束而是错误的。每个请求都应该返回一个资源。在 RESTful 服务中执行布尔问题是一个滑行到 RPC 的过程。

现在我不知道你看到的服务怎么样了。但是解决这个问题的一个好方法是使用一个 Account 对象,您可以尝试获取这个对象。如果您的凭证是正确的,您将得到 Account 对象,如果您不想浪费带宽只是做一个“检查”,您可以做一个 HEAD 对同一资源。

一个帐户对象也是一个很好的地方存储所有那些讨厌的布尔值,否则将是棘手的创建个人资源。

只有在请求需要授权头字段且授权失败时,才应发送401。由于登录 API 不需要授权,因此我认为401是错误的错误代码

根据这里的标准 https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

* 10.4.2401未经授权

请求需要用户身份验证。响应必须包含一个 WWW-Authenticate 头字段(第14.47节) ,其中包含适用于请求资源的挑战。客户端可以使用合适的 Authorization 头字段重复请求(第14.8节)。如果请求已经包含了“授权凭据”,那么401响应指示这些凭据的授权已被拒绝。如果401响应包含与先前响应相同的挑战,并且用户代理至少已经尝试过一次身份验证,那么应该向用户展示响应中给出的实体,因为该实体可能包含相关的诊断信息。HTTP 访问身份验证在“ HTTP 身份验证: 基本和 HTTP摘要认证”中有解释[43]。*

如果401回应码误导用户验证,API 可以发送 HTTP状态码200确定的成功和失败的验证,但设置一个自定义标头的成功验证回应,并忽略该标头的失败登录。

客户端可以检查头是否存在并决定操作。

示例: SpringBootAPI 响应

当登录成功时,对 OK 的调用会将头部“ gotyouin”设置为一个值(任何值)。调用失败不会添加标头,客户端可以将此视为失败的登录尝试。

public class LoginResponseEntityHelper {
public static ResponseEntity<?> ok(String token) {
return ResponseEntity.status(HttpStatus.OK).header("gotyouin", token).body(null);
}


public static ResponseEntity<?> failed() {
return ResponseEntity.status(HttpStatus.OK).body(null);
}}

如果因为请求缺少或有不正确的凭据而拒绝访问资源,那么使用401 HTTP状态码是合乎逻辑的。当提供 正确凭据时,请求应该成功地授予对受限资源的访问权限。
适用于你的情况: myservice.com/this/is/a/user/action

也许我们应该弄清楚这个证件

在大多数安全应用程序中,访问受限资源需要凭据。这些凭据可以通过 HTTP 头(特别是 AuthorizationHeader)沿着后续请求发送。因此,Authorization 标头包含身份验证信息,即凭据。当凭据缺失或无效时,我们可以有效地发送回401响应。

当用户成功登录到应用程序时,将身份验证信息授予用户。

因此,当登录尝试失败时,LoginAPI 不应发送401响应。这是误导。因为您正在请求 LoginAPI 向您授予访问其他受限资源所需的凭据。它是 没有一个受限制的资源。

那么正确的响应状态是什么呢?

嗯,我将发送回一个400响应代码,因为失败的登录尝试是一个客户端错误,没有提供正确的 用户名或密码

根据 RFC标准,大约有400个代码:

400(Bad Request)状态代码表示服务器不能或不会处理请求,因为某些事情被认为是客户端错误(例如,格式不正确的请求语法,无效的请求消息框架,或欺骗性的请求路由)

我将再次重申,由于提供了不正确的详细信息,失败的登录是 客户端错误。发回一个400并不意味着请求语法有问题。但是语法错误是原因之一。

发送401实际上是一种误导,因为用户不需要提供身份验证信息来访问登录 API。