12

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

clientId - docId

路由看起来像这样

/api/controller/clientId/docId

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

有什么方法可以在休息时正确地做到这一点并拥有最好的安全性?

  1. 像上面一样路由,只需根据用户名验证clientId与路由中的相同

或者

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

    /api/controller/docId

这可能是一个显而易见的问题,但我担心潜在的安全问题。还是选择较短的路线只是一个明智的选择?

谢谢!

4

2 回答 2

8

我认为/api/controller/docId可能是最好的主意,或者使用单个代理键来表示 ClientId 和 docId(我的偏好)。

除非您需要允许客户端查看其他客户端资源,否则我会将其隐藏在 URI 方案中,最坏的情况是它可能被认为是信息泄漏,充其量是多余的,因为您已经验证了客户端并且知道他们是谁。这也是一种开销,即您仍然必须检查 url 中的客户端 ID 是否映射到请求的用户名和密码,因此无论如何您都需要检索每个请求的客户端 ID。

如果您查看了其他多租户环境(例如销售人员)的工作方式,您会发现他们必须通过安全机制推断客户端,或者幸运地为每个对象/资源拥有一个唯一的 ID。

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

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

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

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

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

于 2012-12-07T11:39:47.573 回答
7

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

于 2012-12-07T13:55:31.633 回答