125

这是一个概念问题。

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

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

问题是,当我查询 Web 服务只是为了查明给定的用户名/密码是否有效时,Web 服务是否应该始终以 JSON 数据响应告诉我其成功或不成功,或者它是否应该在良好的凭据和 HTTP 上返回 HTTP 200 401 错误凭据。

我问的原因是,即使您只是询问凭据是否有效,其他一些 RESTful 服务也会使用 401 作为错误凭据。但是,我对 401 响应的理解是,它们代表了您在没有有效凭据的情况下不应访问的资源。但是任何人都应该可以访问登录资源,因为登录资源的全部目的是告诉您您的凭据是否有效。

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

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

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

myservice.com/are/these/credentials/valid

永远不应返回 401,因为该特定 URL(请求)被授权使用或不使用有效凭据。

我想以一种或另一种方式听到一些合理的意见。处理这个的标准方式是什么,处理这个的标准方式在逻辑上是否合适?

4

4 回答 4

147

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

401 Unauthorized 类似于 403 Forbidden,但专门用于需要身份验证但已失败或尚未提供身份验证时使用。响应必须包含一个 WWW-Authenticate 标头字段,该字段包含适用于所请求资源的质询。

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

现在我不知道您查看的服务的行为如何。但是解决这个问题的一个好方法是拥有一个像 Account 对象一样的东西,你可以尝试 GET。如果您的凭据正确,您将获得 Account 对象,如果您不想浪费带宽只是为了进行“检查”,您可以在同一资源上执行 HEAD。

帐户对象也是存储所有那些讨厌的布尔值的好地方,否则这些布尔值很难为其创建单独的资源。

于 2012-07-30T02:22:05.307 回答
33

仅当请求需要授权头域且授权失败时才应发送 401。由于登录 API 不需要授权,因此在我看来 401 是错误的错误代码

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

*10.4.2 401 未经授权

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

于 2018-08-02T13:09:38.683 回答
0

如果 401 响应代码误导用户身份验证,API 可以发送 HTTP 状态代码 200 OK 来表示成功和失败的身份验证,但在身份验证成功响应上设置自定义标头,并在登录失败时省略该标头。

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

示例:SpringBoot API 响应

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

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);
    }}
于 2021-04-09T08:28:33.953 回答
-6

返回 409 并带有正确的错误消息。

于 2019-11-13T19:00:56.257 回答