HTTP API:向第三方传达身份验证的需要
HTTP API: Communicating the need to authenticate to a third party
我正在开发 RESTful API,其中包括 third-party 集成。我们将 OAuth 与授权代码流结合使用以针对第三方进行身份验证。用户必须先登录我们的服务,然后再额外登录第三方,这样我们的应用才能访问第三方。
我们的一些资源需要与第三方交互才能完成(比如 GET /third-party-userpic
)。如果用户已经登录到该服务,我们将从我们的数据存储中检索访问令牌并使用它来检索用户的图片,简单!
但是,如果我们不持有该用户使用该服务的有效凭据,我们将无法获取该用户的照片。这将在首次使用时发生,如果凭据过期或被撤销也可能发生。在这种情况下,我们希望与客户端沟通他们需要访问授权 URI 并开始 OAuth 流程。
我和我设计这个的同事讨论了几种可能性,包括:
- 返回
200 OK
成功,并指示在响应 body 中需要或允许身份验证。这是不优雅的,不能很好地扩展到不同的资源 content-types,并且要求客户端知道它何时访问可能需要此身份验证方案的资源。
- 返回
403 Forbidden
和 link 以在 headers 或 body 中进行身份验证。问题在于,这需要与由于权限问题而生成的 403 Forbidden
区分开来,感觉与我们想要 403
的意思不符。
- 返回
401 Unauthorized
。这有同样的问题,要求客户端在用户未登录时将其与我们平台生成的 401
分开。还有一个额外的问题,即 401 Unauthorized
是 HTTP challenge-response 身份验证方案,但我们未在此处实施 challenge-response 流程。客户端永远不会触及凭据。
- 正在创建一个新的
4XX
状态代码,以允许客户端轻松地将这种情况与其他可能的故障区分开来。从技术角度来看,这似乎是最干净的,但制作新的状态代码并不是我们可能需要做的事情!
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.
上的流程图操作时将获得的响应代码
我正在开发 RESTful API,其中包括 third-party 集成。我们将 OAuth 与授权代码流结合使用以针对第三方进行身份验证。用户必须先登录我们的服务,然后再额外登录第三方,这样我们的应用才能访问第三方。
我们的一些资源需要与第三方交互才能完成(比如 GET /third-party-userpic
)。如果用户已经登录到该服务,我们将从我们的数据存储中检索访问令牌并使用它来检索用户的图片,简单!
但是,如果我们不持有该用户使用该服务的有效凭据,我们将无法获取该用户的照片。这将在首次使用时发生,如果凭据过期或被撤销也可能发生。在这种情况下,我们希望与客户端沟通他们需要访问授权 URI 并开始 OAuth 流程。
我和我设计这个的同事讨论了几种可能性,包括:
- 返回
200 OK
成功,并指示在响应 body 中需要或允许身份验证。这是不优雅的,不能很好地扩展到不同的资源 content-types,并且要求客户端知道它何时访问可能需要此身份验证方案的资源。 - 返回
403 Forbidden
和 link 以在 headers 或 body 中进行身份验证。问题在于,这需要与由于权限问题而生成的403 Forbidden
区分开来,感觉与我们想要403
的意思不符。 - 返回
401 Unauthorized
。这有同样的问题,要求客户端在用户未登录时将其与我们平台生成的401
分开。还有一个额外的问题,即401 Unauthorized
是 HTTP challenge-response 身份验证方案,但我们未在此处实施 challenge-response 流程。客户端永远不会触及凭据。 - 正在创建一个新的
4XX
状态代码,以允许客户端轻松地将这种情况与其他可能的故障区分开来。从技术角度来看,这似乎是最干净的,但制作新的状态代码并不是我们可能需要做的事情!
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.
上的流程图操作时将获得的响应代码