具有客户端分隔的多租户数据库的Rest API

Ben*_* E. 11 rest asp.net-web-api

我有一个带有复合键的多租户数据库

clientId - docId
Run Code Online (Sandbox Code Playgroud)

路由看起来像这样

/api/controller/clientId/docId
Run Code Online (Sandbox Code Playgroud)

对于身份验证,我使用"全局"用户名,例如电子邮件+密码,通过https在每个请求的http-header中发送.用户名明确映射到客户端,并在后端可用.

有什么方法可以正确地进行休息并获得最佳安全性?

  1. 如上所述路由,只需验证根据用户名的clientId与路由中的相同

要么

  1. 如下所示更改路由并在保存记录之前从数据库获取clientId?

    /api/controller/docId

这可能是一个显而易见的问题,但我担心潜在的安全问题.或者使用较短的路由只是一个明智的选择?

谢谢!

Mar*_*nes 8

我认为/api/controller/docId可能是最好的想法或使用单个代理键来表示ClientId和docId(我的偏好).

除非您需要允许客户端查看其他客户端资源,否则我会将其隐藏在URI方案中,在最坏的情况下,最好将信息泄漏视为冗余,因为您已经对客户端进行了身份验证并知道他们是谁.它也是一个开销,即您仍然必须检查URL中的客户端ID是否映射到请求的用户名和密码,因此您需要在每个请求上检索客户端ID.

如果您查看其他多租户环境如何工作,例如Sales Force,您可以看到他们必须通过安全机制推断客户端,或者幸运的是,每个对象/资源都有唯一的ID.

我看到的一种方法是在URL的根目录下放置客户端标识符(通常是somekind的代理键,避免暴露其他用户db id!),例如/ api/{clientId}/controller/docId.在多租户环境中,每个资源可能/根据定义对该客户端是唯一的.

有时给出这种方法的原因是每个客户有一个唯一的URL协助缓存.../api/{clientId}/controller/docId或/ api/controller/{clientId}/docId

关于基本身份验证的简要说明

您的方法没有错,但考虑......您可以在验证密码和用户名的同时检索客户端ID,并将其添加为IPrinciple上的声明.然后,至少可以在代码中找到它,而不需要任何进一步的数据库查找(在该请求的生命周期内).

更进一步......考虑一个两步认证机制,其中发布令牌(遵循正确的用户名和密码),其中客户端Id实际上在令牌中作为声明.这样,使用令牌的后续请求意味着您不需要为每个验证和检索信息的请求回调数据库.看一下OAuth bearer令牌http://self-issued.info/docs/draft-ietf-oauth-v2-bearer.html(一定要签名)或其他一些方法......


Dar*_*ler 7

Mark的方法完全有效,但是,我碰巧使用,/tenant/docid因为每个租户都有不同的数据库.如果您没有在URI中包含租户,那么尝试确定连接到哪个数据库并寻找文档将是一个真正的痛苦.

  • @bjornhol如果租户ID未包含在URL中,那么它会使本地缓存变得困难,因为我使用整数而不是guid用于标识符,因此租户之间可能存在冲突. (3认同)