HTTP API:向第三方传达身份验证的需要

HTTP API: Communicating the need to authenticate to a third party

我正在开发 RESTful API,其中包括 third-party 集成。我们将 OAuth 与授权代码流结合使用以针对第三方进行身份验证。用户必须先登录我们的服务,然后再额外登录第三方,这样我们的应用才能访问第三方。

我们的一些资源需要与第三方交互才能完成(比如 GET /third-party-userpic)。如果用户已经登录到该服务,我们将从我们的数据存储中检索访问令牌并使用它来检索用户的图片,简单!

但是,如果我们不持有该用户使用该服务的有效凭据,我们将无法获取该用户的照片。这将在首次使用时发生,如果凭据过期或被撤销也可能发生。在这种情况下,我们希望与客户端沟通他们需要访问授权 URI 并开始 OAuth 流程。

我和我设计这个的同事讨论了几种可能性,包括:

https://www.rfc-editor.org/rfc/rfc6750 建议如下:

  • 客户端负责请求访问范围,基本上您的主要功能和第三方功能应该描述为单独的范围
  • 如果客户端试图访问资源(在你的情况下是一些第三方功能)而不请求访问它,服务器应该响应 403 响应 insufficient_scope 错误

insufficient_scope The request requires higher privileges than provided by the access token. The resource server SHOULD respond with the HTTP 403 (Forbidden) status code and MAY include the "scope" attribute with the scope necessary to access the protected resource.

WWW-Authenticate: Bearer realm="myprotectedresource", 
     error="insufficient_scope", 
     error_description="Insufficient scope for this resource scopes", scope="SOME_SCOPE"

以下为同源授权流程图

 +--------+                               +---------------+
 |        |--(A)- Authorization Request ->|   Resource    |
 |        |                               |     Owner     |
 |        |<-(B)-- Authorization Grant ---|               |
 |        |                               +---------------+
 |        |
 |        |                               +---------------+
 |        |--(C)-- Authorization Grant -->| Authorization |
 | Client |                               |     Server    |
 |        |<-(D)----- Access Token -------|               |
 |        |                               +---------------+
 |        |
 |        |                               +---------------+
 |        |--(E)----- Access Token ------>|    Resource   |
 |        |                               |     Server    |
 |        |<-(F)--- Protected Resource ---|               |
 +--------+                               +---------------+

with an indication that authentication is required or permitted in the response body somehow

我认为这在很大程度上取决于“要求”与“允许”:否则您能否成功完成请求,只丢失一部分结果?

如果可以(并且想要),也许是这样的:

HTTP/1.1 200 OK
Date: Tue, 10 May 2016 01:08:07 GMT
Content-Type: application/vnd.whatever+json
Link: <https://third-party.example/authorize>;
    rel="https://example.com/doc/#authorize-3rd-party"
Warning: 299 - "part of the content is missing; authorize with third party"

...content with only the pic missing...

如果你不能(或不想),那么 424 (Failed Dependency), 403 (Forbidden) (but see comments), and 400 (Bad Request) all sound like they might be appropriate status codes. However, status codes are not a solution to every problem. It’s perfectly normal to refine their meaning in the response payload. There’s even a new standard for this—RFC 7807:

HTTP/1.1 400 Bad Request
Date: Tue, 10 May 2016 01:08:07 GMT
Content-Type: application/problem+json

{
    "type": "https://example.com/doc/#authorize-3rd-party",
    "title": "You need to authorize with a third party for this.",
    "authorizeAt": "https://third-party.example/authorize"
}

您对 401(未授权)和发明自己的状态代码的疑虑是非常正确的。

首先:我很难相信显示用户图片是一个关键组成部分,所以我认为这比用户被谴责为由默认头像代表的后果更大。

在这种情况下,2xx-class 响应代码几乎是不可能的,因为操作没有成功。虽然服务器端的机制失败了,但客户端有机会纠正这个问题(通过 OAuth 进行身份验证)。这排除了 5xx-class 状态代码,建议 4xx-class.

正如您正确断言的那样,401 不太正确,因为此代码特定于所请求的资源。来自 RFC 7235, section 3.1:

The 401 (Unauthorized) status code indicates that the request has not been applied because it lacks valid authentication credentials for the target resource.

但是,您的目标资源是可以的;这是一个麻烦的外部服务。除此之外,401 将带您进入 HTTP 身份验证框架的核心,它引入了许多实际问题。

这个范围内最合适的状态码确实是403。来自RFC 7231, section 6.5.1:

The 403 (Forbidden) status code indicates that the server understood the request but refuses to authorize it. A server that wishes to make public why the request has been forbidden can describe that reason in the response payload (if any).

虽然一开始这听起来可能无关紧要,但请考虑一下

[...] a request might be forbidden for reasons unrelated to the credentials.

RFC 还显示:

The client MAY repeat the request with new or different credentials.

所以这段代码很宽松,因为它不是特定于所请求的资源,而是很好地考虑了阻止成功操作的其他情况。这也是您按照 Choosing an HTTP Status Code — Stop Making It Hard.

上的流程图​​操作时将获得的响应代码