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

很多关于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 |
+-------------+----+-------+-----------+

问题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
|

每个客户应允许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

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

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

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

GET /pets HTTP/1.1
Host: www.example.org
Authorization: bob:c29kYW9kYSBhb2lzYWRoIGYgZDUzNDUz

可能性#2。 tenant_id作为查询参数发送:

GET /pets/tenant_id=1 HTTP/1.1
Host: www.example.org
Authorization: bob:c29kYW9kYSBhb2lzYWRoIGYgZDUzNDUz

第1部分

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

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

参考文献:

  • 保护API:SSL和HTTP基本身份验证与签名
  • 有关HMAC与备选方案的良好比较,请参阅什么是HMAC验证以及它为何有用?
  • AviD指出的一个警告是“如果通过HTTPS完成,BASIC-Auth安全吗?” “SSL只能保护网络服务器 - 任何内部路由,服务器日志记录等都会看到明文密码。”
  • 更新 :以下是关于如何处理auth的一些额外细节:

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

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

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

  • 但是,你如何首先获得客户的钥匙? 构建“关键请求”API端点。 我建议给每个客户端一个“启动器”键,只用于联系这个端点。 (起始键不允许其他访问。)当用户第一次使用客户端时,他/她必须进行身份验证。 客户端将其传递给“密钥请求”端点,以便它可以生成与用户关联的密钥。 从那以后,每个客户端都有一个客户端绑定的API密钥。

  • 第2部分

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

    GET http://tenant1.app.co/pets
    GET http://tenant2.app.co/pets
    GET http://tenant3.app.co/pets
    

    参考文献(Rails特有的,但应该对整个Web栈有所帮助):

  • 在Rails中编写多租户应用程序
  • 将多租户添加到您的Rails应用程序:acts_as_tenant
  • Rails中的多租户
  • 请注意:正如您的示例所示,为了简单起见,我不会为不同的租户重复使用相同的宠物ID。 例如,以下是一个简单的方法:

    GET http://tenant1.app.co/pets/200
    GET http://tenant2.app.co/pets/201
    GET http://tenant3.app.co/pets/202
    

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

    参考文献:

  • 多租户数据库体系结构 - 第5部分
  • “如果查询字符串参数是一个算法的资源的输入,那么这些参数是合适的。否则,这些值应该移到URI中 - ”维基百科上面向资源的体系结构

  • 通过“多租户”,你是否只是指应用程序/ Web服务用户? 多租户通常意味着更复杂的事情msdn.microsoft.com/en-us/library/aa479086.aspx。

    您需要使用您的Web服务来验证每个用户。 这可以通过SSL的基本http身份验证完成。

    从Web服务的角度来看,您将对所有三个客户端执行相同的身份验证。 该服务不关心客户的类型 - 这就是要点。 这可能是因为你需要为你的客户提供不同的表述,例如XHTML或JSON。 我喜欢将事情简单化并始终选择JSON。

    对于资源,管理它们的最简单方法是将用户资源作为最高级别,然后将所有资源链接到每个用户,例如

    GET users/fred/pets - returns all pets for user fred
    GET users/fred/pets/sparky - returns details on freds pet sparky
    

    这样做的好处在于您可以添加代码来授权每个请求,例如,您可能有两个用户,fred和jack。 两个用户都会通过身份验证,但你只应该允许fred请求他的资源和插口来请求他的。 你只需要在你的API中添加授权检查,例如从URI获取用户名,获取经过验证的用户的用户名,检查它们是否相同。 如果不返回类似http 403的内容,如果它们相同,则允许请求。

    我想如果你还不清楚,你需要阅读REST的细节。 到目前为止,关于这个主题的最好的书是这一个RESTful Web服务。 它涵盖了来自第一原则的REST。 它在设计资源,以及如何管理用户和多个客户端方面也有非常好的一面。


    我不确定要理解这个问题,因为在这种情况下多租户似乎有点矫枉过正。 不过,我可以尝试回答第二个问题。

    REST是一种“基于资源”的体系结构,您必须认识到/pets/pets/?tenant=1不会引用相同的资源:

  • /pets是指当前用户的宠物,
  • /pets/?tenant=1是指Bob的宠物。
  • 虽然这两种解决方案都没有错,但通常情况下最好是获得第二种解决方案 URI的确被设计为共享,并且你有更多的理由来分享“Bob的宠物”(即使它需要认证和授权来表示),而抽象的“我的宠物”对每个用户都不相同。

    请参阅资源ID是否应存在于网址中? 进行类似的讨论...

    链接地址: http://www.djcxy.com/p/21971.html

    上一篇: What is the correct way to authorize and structure a RESTful backend

    下一篇: Supplying credentials safely to a RESTFUL API