2013-02-28 51 views
7

很多有关RESTful Web服务的示例都没有考虑到今天许多应用程序都是多用户的问题。什么是授权和构建RESTful后端的正确方式

想象一下多用户后台暴露了一个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:与三个或更多与REST风格的后端交互的客户端应用程序(例如Android,iOS和Web应用程序),你会如何进行认证对后端?

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的样子?

这里有方法可以得到Bob的宠物两种可能性:

可能性#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 
+0

使用短语multi-tenant时要小心。我不相信它意味着你的想法。在这里看到细节http://msdn.microsoft.com/en-us/library/aa479086.aspx – 2013-03-04 19:23:45

+0

@Gaz_Edge它意味着虚拟分区数据在客户端和单个实例将服务更多的客户,这就是我正在做的事情。你同意吗? – gremo 2013-03-04 20:28:01

+1

我觉得你太过于复杂了。您有1个Web服务,n个Web服务客户端和x个用户是? – 2013-03-04 22:28:02

回答

4

第1部分

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

我建议HTTPS使用基本验证。简单。毕竟,Stripe已经足够好了。

参考文献:

更新:下面是关于如何处理身份验证一些额外的细节:

  1. 每个客户端应用程序将使用API​​密钥联系服务。使用HTTPS和基本身份验证,客户端将提供其API密钥作为基本身份验证用户名。它不需要提供密码,因为它使用的是HTTPS。你需要指定一个API密钥对每个应用程序(Web应用程序,安卓,iOS版),我看到了两个方面:

    A.一种选择是,得到跨客户端共享的每个用户一个API密钥。

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

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

第2部分

考虑给每个租户的子域。如果您使用的Rails(或者可能是任何现代的网络堆栈),您可以使用子域名查找租户ID。那么你的API可用于这样的:

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

引用(Rails的具体的,但应该是整个网络栈有帮助):

注:如你的例子表明,为了简单起见,我将不属于R为不同的租户电子使用同一个宠物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作为参数感觉不对。我喜欢用的参数更多的“算法”的事情,正如我在“REST Web服务”,由Ruby和理查德森阅读。

参考文献:

+0

我喜欢第2部分,我会去寻找子域名。但是第1部分没有解释验证每个应用程序对后端的挑战。也许这是我可怜的英语,我无法深入解释这个问题。我选择了HMAC,因为请求之间没有状态。为什么你建议Basic? – gremo 2013-03-08 15:18:02

+0

我建议使用HTTPS + Basic Auth,因为这是最简单的方法。如果你想挖掘所有的优点和缺点,我提供了参考。 – 2013-03-08 17:48:22

+0

@Gremo,我刚刚添加了关于第1部分(auth)的一些额外的细节。 – 2013-03-08 18:07:46

3

通过“多租户”你仅仅意味着应用程序/ 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 Services。它涵盖了来自第一原则的REST。它在设计资源,以及如何管理用户和多个客户端方面也有非常好的一面。

+0

我会编辑问题以使其更加清晰。与此同时:我只有一个Web服务(RESTful后端)和'n'可能的客户端(应用程序)使用它。用户(租户)将使用其中一个'n'客户端(可能甚至更多,即webapp和android客户端)。 – gremo 2013-03-04 17:49:44

+0

我想给Gaz一个upvote,所以他/他没有得分666. – 2013-03-08 14:11:47

+0

awww,但我喜欢它! ;-) – 2013-03-08 16:50:08

1

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

REST是一种“资源化”的建筑,你必须认识到/pets/pets/?tenant=1并不是指在相同的资源:

  • /pets是指当前用户的宠物,
  • /pets/?tenant=1指鲍勃的宠物。

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

Should resource ids be present in urls?了类似的讨论......

1

如果HTTP协议的所有3客户端类型使用,你应该只需要实现一个认证方案。你可以选择你的毒药 - BasicDigest,Oauth2Cookie是一些常用的方法。由于它是通过HTTP,我没有理由复制这个逻辑。根据您的平台,可能有几个框架将为您抽象。

要区分客户端类型,可以使用HTTP标头user-agent可能已经使这成为可能。另一种选择是使用您定义的自定义标题。任何HTTP客户端都可以设置标题,任何服务器都可以处理自定义标题。一个体面的web框架将相对容易地为您提供这些框架。作为后端服务,我怀疑您会希望统一处理所有客户端请求 - 或尽可能多地处理。当然,维护一个后端优于三个

至于你的API应该是什么样子 - 这完全取决于你。为了保持RESTful,how to GET a cup of coffee非常值得阅读 - 插入强制性链接Roy Fielding's thesis。机会是,你真正想要的是编写'资源'链接的指南。

如果用户可能需要访问系统中的所有宠物,则在您列出的选项中,首选第二个,即/pets?userId=bob。如果用户只需要访问他们的宠物,则首选/pets

相关问题