授权和构建RESTful后端的正确方法是什么?

gre*_*emo 7 api rest authorization web-services restful-authentication

关于RESTful Web服务的大量示例没有考虑到当今许多应用程序是多用户的问题.

想象一下,暴露RESTful API多用户后端.后端数据体系结构使用共享数据库和共享模式.每个表都包含对以下内容的引用tenant_id:

+-------------+----+-----------------+
|  tenant_name| id |   shared_secret |
+-------------+----+-----------------+
|         bob |  1 |   2737sm45sx543 |
+-------------+----+-----------------+
|       alice |  2 |   2190sl39sa8da |
+-------------+----+-----------------+

+-------------+----+-------+-----------+
|    pet_name | id |  type | tenant_id |
+-------------+----+-------+-----------+
|       fuffy |  1 |   dog |         1 |
+-------------+----+-------+-----------+
|       kerry |  2 |   cat |         2 |
+-------------+----+-------+-----------+
Run Code Online (Sandbox Code Playgroud)

问题1:如果有三个或更多客户端应用程序(即Android,iOS和Web App)与RESTful后端交互,您将如何对后端执行身份验证?

RESTful backend, API, HTTP-Verbs, shared database and schema 
|
|
+---- Web Application (Client 1)
|     |
|     + Alice
|     |
|     + Bob
|
+---- Android Application (Client 2)
|     |
|     + Alice
|     |
|     + Bob
|
+---- iOS Application (Client 3)
|     |
|     + Alice
|     |
|     + Bob
|
Run Code Online (Sandbox Code Playgroud)

每个客户都应该允许Alice和Bob管理她/他的宠物.每个客户端都是一个GUI,它将在后端使用(内部,发出HTTP请求).问题:每个客户端如何针对后端进行身份验证?

假设HMAC(它完全是RESTful,没有会话):这种方法涉及使用共享密钥签署有效负载(从不通过线路发送).每个客户都应该拥有自己的tenant表副本(包含该shared_secret字段)吗?

Android App -> Client Sign -> Signed Request -> Backend -> Result
    Web App -> Client Sign -> Signed Request -> Backend -> Result
Run Code Online (Sandbox Code Playgroud)

问题2:资源URI应该是什么样的?

以下是获取鲍勃宠物的方法的两种可能性:

可能性#1:Authorization标题为您提供租户(唯一)名称:

GET /pets HTTP/1.1
Host: www.example.org
Authorization: bob:c29kYW9kYSBhb2lzYWRoIGYgZDUzNDUz
Run Code Online (Sandbox Code Playgroud)

可能性#2.将tenant_id被作为查询参数:

GET /pets/tenant_id=1 HTTP/1.1
Host: www.example.org
Authorization: bob:c29kYW9kYSBhb2lzYWRoIGYgZDUzNDUz
Run Code Online (Sandbox Code Playgroud)

Dav*_* J. 4

第1部分

\n\n

(大声思考:您是否已经决定使用 HTTP 和 HMAC?如果是,为什么还要问我们?)

\n\n

我建议使用带有基本身份验证的 HTTPS。简单的。毕竟这对于Stripe来说已经足够好了。

\n\n

参考:

\n\n\n\n

更新:以下是有关如何处理身份验证的一些其他详细信息:

\n\n
    \n
  1. 每个客户端应用程序都将使用 API 密钥联系服务。使用 HTTPS 和基本身份验证,客户端将提供其 API 密钥作为基本身份验证用户名。它不需要提供密码,因为它使用 HTTPS。您需要为每个应用程序(Web 应用程序、Android、iOS)分配一个 API 密钥,我看到两种方法:

    \n\n

    答:一种选择是为每个用户提供一个在客户端之间共享的 API 密钥。

    \n\n

    B. 另一种选择是为每个客户提供一个独特的应用程序。)

  2. \n
  3. 但首先如何获得客户的钥匙呢?构建“关键请求”API 端点。我建议为每个客户端提供一个仅用于联系此端点的“启动”密钥。(启动密钥不会授予其他访问权限。)当用户首次使用客户端时,他/她必须进行身份验证。客户端将其传递到“密钥请求”端点,以便它可以生成与用户关联的密钥。从那时起,每个客户端都有一个与客户端绑定的 API 密钥。

  4. \n
\n\n

第2部分

\n\n

考虑为每个租户提供一个子域。如果您使用 Rails(或者可能任何现代 Web 堆栈),您可以使用子域来查找租户 ID。然后你的 API 可以这样使用:

\n\n
GET http://tenant1.app.co/pets\nGET http://tenant2.app.co/pets\nGET http://tenant3.app.co/pets\n
Run Code Online (Sandbox Code Playgroud)\n\n

参考资料(特定于 Rails,但应该对跨 Web 堆栈有帮助):

\n\n\n\n

注意:正如您的示例所示,为简单起见,我不会为不同的租户重复使用相同的宠物 ID。例如,以下是一个简单的方法:

\n\n
GET http://tenant1.app.co/pets/200\nGET http://tenant2.app.co/pets/201\nGET http://tenant3.app.co/pets/202\n
Run Code Online (Sandbox Code Playgroud)\n\n

我描述的方法比tenant_id作为查询参数传递要干净得多。此外,用作tenant_id参数感觉不对。我喜欢将参数用于更多“算法”事物,正如我在 Ruby 和 Richardson 所著的“RESTful Web Services”中读到的那样。

\n\n

参考:

\n\n\n