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

136

这是一个概念性问题。

我有一个客户端(移动端)应用程序,需要支持对RESTful网络服务进行登录操作。由于该网络服务是RESTful的,这意味着客户端需要接受用户提供的用户名/密码,验证该用户名/密码并记住在所有后续请求中发送该用户名/密码。

该网络服务中的所有其他响应都以JSON格式提供。

问题是,当我查询网络服务仅了解特定用户名/密码是否有效时,该网络服务应该始终用返回JSON数据告诉我其是否成功或失败,还是应该在凭证正确时返回HTTP 200,在凭证错误时返回HTTP 401。

我之所以问这个问题是因为有些其他RESTful服务即使你只是询问凭据是否有效,也会使用401表示凭证无效。然而,我对401响应的理解是它们代表您没有合法凭证访问的资源。但是,登录资源应该可供任何人访问,因为登录资源的整个目的就是告诉您您的凭证是否有效。

换句话说,对于类似这样的请求:

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

如果提供了错误的凭据,应该返回401。但是像这样的请求:

myservice.com/are/these/credentials/valid

这个特定的URL(请求)无论有没有有效凭证都是授权的,因此不应该返回401错误。

我想听听大家对此的合理观点。处理此问题的标准方式是什么?这种处理方式在逻辑上是否正确?

5个回答

152

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

401未授权 类似于403禁止访问,但专门用于身份验证失败或尚未提供身份验证的情况。响应必须包含一个WWW-Authenticate头字段,其中包含适用于所请求资源的挑战。

你对于 myservice.com/are/these/credentials/valid 返回401的困惑,我认为是基于在REST中使用布尔请求往往是不符合RESTful规范的事实。每个请求应返回一个资源。在RESTful服务中进行布尔查询是一条下滑到RPC的 slippery sloop(意为悬崖式下滑)。

现在我不知道你所查看的服务行为如何。但解决这个问题的好方法是有一个像“账户”对象这样的东西,您可以尝试GET该对象。如果您的凭据正确,则会获取该帐户对象;如果您不想浪费带宽来仅仅进行“检查”,则可以在同一资源上执行HEAD操作。

帐户对象还是存储所有那些棘手的布尔值的好地方,否则将为创建单独的资源而变得棘手。


2
你提到归还资源的观点似乎是正确的,也许这是正确的做法。至于说401是正确的响应,我希望能够得到一些解释。我已经阅读了HTTP规范,就像你在这里所包含的那样,但对我来说,这并不是对你的断言的直接和明显的确认。也就是说,身份验证不是必需的,以询问凭据的有效性 - 然而你所包含的内容却说“特别用于需要身份验证的情况”。 - Matt
4
你的看法是正确的。你不需要进行身份验证就可以请求账户对象。但是,你需要成功地进行身份验证才能够接收资源,这就是authentication is required and has failed or has not yet been provided所适用的情况,因为你不是在要求凭证的有效性,而是基于你提供的凭证来请求特定的资源。 - Cleric
2
我理解你为什么想要进行“检查调用”,对此,即使该调用不需要身份验证也失败了,我仍然会推荐使用401作为适当的响应代码。204无内容也可能是合适的,但感觉有些含糊不清。 - Cleric
8
我认为这个说法不正确,除非你正在使用基本或摘要身份验证。根据规范中引用的部分:“响应必须包括WWW-Authenticate” - 如果您参考第14.47节:“HTTP访问验证过程在“HTTP身份验证:基本和摘要访问验证”中进行了描述。” 这对我意味着,如果您正在使用典型的电子邮件/密码验证,则401是不适当的。 - Jonah
1
我认为这可能是错误的,因为我一直在实现Web和移动客户端,并拦截401以重定向到登录屏幕。但是当有人已经在登录屏幕上并提交错误凭据时,响应也会返回401并尝试再次重定向。在明确尝试进行身份验证时,应该有一个不同的状态代码来表示身份验证失败的尝试。也许是错误请求甚至是服务器错误? - Japheth Ongeri - inkalimeva
显示剩余6条评论

43

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

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

*10.4.2 401未经授权*

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


24
我同意你的看法,但是应该发送哪种备选的响应状态呢?我一直在实现网站和移动客户端,我会拦截401状态码并将其重定向到登录界面。但是当有人已经处于登录界面并提交错误的凭据时,响应也会返回401并尝试再次重定向...那么你会怎么做呢? - Japheth Ongeri - inkalimeva
1
这看起来是正确的。根据定义,登录请求不需要授权。那么它怎么可能授权失败呢!这毫无意义。我认为403或404是正确的响应,因为我们无法使用输入访问资源。 - SmileBot
我完全同意这一点,这也是我设计API的方式。我知道我们通常将其视为身份验证端点。如果我们将其视为另一个资源(即使“资源”是布尔值),那么返回404 Not Found是正确的,因为提供的有效载荷未找到任何用户名和密码与记录匹配的资源。因此,在我看来,返回404 Not Found是正确的。 - RoLYroLLs
@RoLYroLLs 404 表示登录/认证端点不存在。请使用400或422。 - Joel Mellon

5
当请求缺少或具有不正确的凭据时,使用401 http状态代码拒绝访问资源是合乎逻辑的。当提供正确的凭据时,请求应成功完成,允许访问受保护的资源。
适用于您的情况:myservice.com/this/is/a/user/action

也许我们应该明确这些凭据

在大多数安全应用程序中,需要凭据才能访问受保护的资源。这些凭据可以通过HTTP标头随每个请求发送。特别是Authorization标头
因此,授权标头包含允许用户访问受保护资源的凭据

请记住,已成功验证为授权用户(成功登录)的用户是被赋予这些特权凭据以允许访问服务器上的受保护资源的用户。

从服务器的角度来看,针对受保护资源的HTTP请求如果缺少凭据或包含无效凭据可能会导致有效地发送回401响应代码
因此,登录API不应该因为登录尝试失败而发送401响应代码。这是具有误导性的。原因在于您通过Login API向服务器应用程序请求授予您访问受保护资源所需的凭据。单独的Login API本身不是受保护资源。
那么正确的响应状态是什么?
我认为应该发送回400响应代码,因为登录尝试失败是客户端错误,客户端未能提供正确的用户名或密码
根据RFC关于400代码的标准:
400(错误请求)状态码表示服务器无法或不会处理请求,因为它认为是客户端错误(例如,请求语法错误、无效的请求消息格式或欺骗性的请求路由等)。
我再次强调,登录失败是一个“客户端错误”,因为提供了不正确的详细信息。发送400并不一定意味着请求语法有误。但是,语法错误是其中之一的原因。
发送401会让人产生误解,因为用户不需要提供身份验证信息即可访问登录API。

422是另一个可能性,越来越流行用于验证错误。 - Joel Mellon

1
如果401响应代码对用户身份验证具有误导性,API可以发送HTTP状态码200 OK,用于成功和失败的身份验证,但在身份验证成功的响应中设置自定义标头,并在登录失败时省略该标头。
客户端可以检查标头是否存在并决定采取的操作。
例如:SpringBoot API响应
当登录成功时,调用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);
    }}

200 可以使用可选的头部或负载。还有其他可能性。404 在这里也是可能的,因为该资源可能无法使用参数访问。 - SmileBot
@SmileBot 404 表示登录/认证终点不存在。请使用400或422。 - Joel Mellon

0
我认为登录失败的有效响应是409(冲突),因为它暗示着所提交的内容有问题
401意味着请求的资源需要授权,而登录不需要。
403或404意味着请求本身有问题,尽管使用其中之一也是有效的。

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