【问题标题】:ASP.NET Multi tenant application with tenant specific roles具有租户特定角色的 ASP.NET 多租户应用程序
【发布时间】:2014-02-10 08:47:02
【问题描述】:

我们有一个多租户 ASP.NET 应用程序。到目前为止,租户已经相互隔离,但是现在我们有管理多个租户的代理,并且希望能够使用单个用户帐户管理所有租户。我正在尝试找出实现这一目标的最佳方法,希望不会对我们正在使用的现有技术做出太大改变。

相关技术细节:

  • 成员和角色的 AspNetSqlMembershipProvider
  • C# 4.0(即将成为 4.5)
  • 表单验证
  • aspx 和 MVC (v3) 页面
  • 假设有 100 个或更多租户,因此任何解决方案都需要支持这一点

我相信这些要求与 SQL Server 的安全模型非常相似。我们有一组登录名,代表所有可以登录系统的用户。用户应该能够被赋予一个或多个数据库(租户)的角色。示例:用户 Bob 在公司 A 中具有管理员角色,但在公司 B 中只有用户角色。我们还为我公司的员工提供“系统管理员”角色,它允许我们访问任何租户以及特殊的管理权限,例如创建/删除租户等。

我对各种库、框架等进行了大量研究,但我没有找到任何令人信服的证据表明其他库或框架会比我们目前拥有的更好。所以我目前正在考虑如何让 Sql Membership 提供者做我想做的事,除非有人能指出我更好的方向。我也不确定我是否知道在此搜索的最佳字词。

我正在考虑两个选项:

  1. 仅向成员资格提供者添加少数角色,并在成员资格提供者之外处理“当前用户在此租户中是否具有此角色”的所有问题。成员资格提供者将用于处理对系统的基本访问。
  2. 将租户特定角色添加到成员资格提供商。我们将在系统中拥有(角色数)x(租户数)个总角色。每个新租户都会向系统添加另一组角色,例如“Tenant A:Admin”、“Tenant A:User”等。需要一些额外的表来管理关系,可能还需要一些自定义代码来确保访问权限从成员资格提供者那里请求正确的租户特定角色。

这些选项中的任何一个都好吗?还是我应该在其他地方寻求支持?

【问题讨论】:

  • 嗨 Ted,我最近在这里回答了一个类似的问题,也许有用:stackoverflow.com/q/21165928/304832 简而言之,我认为选项 #1 将是最好的选择。
  • 听起来像是在会员提供者之外处理租户特定角色,让会员提供者进行粗粒度访问是可行的方法。

标签: c# asp.net asp.net-mvc-3 asp.net-membership roleprovider


【解决方案1】:

我认为您无法将多租户硬塞到任何开箱即用的角色提供程序中,因此您最好继续使用 SqlMembershipProvider(和 SqlRoleProvider)。即使是最新的 Microsoft.AspNet.Identity 仍然假设用户和角色之间是普通的多对多。您真正需要的是在该多对多表的主键中添加第三列,这将标识您的租户,即:

user: 6
role: 4
tenant: 17

user: 6
role: 9
tenant: 18 (and so on)

...这样,您就可以让用户在不同的租约中拥有不同的权限,所有用户都使用相同的角色名称集。

如果您选择选项 #2,那么您的 [Authorize] 属性将会爆炸。想象一下:

[Authorize(Roles = "TenantA:Admin", "TenantB:Admin", ...)]
public ActionResult Post(int id, SomeViewModel model) {}

...所有这些属性都必须在编译时编写,除非您使用自定义 AuthorizeAttribute,您可以这样做。但即便如此,每次将租户添加到系统时,您仍会创建一组新角色,这应该是不必要的。

【讨论】:

  • 我正在使用您的第一种方法,并在我的 ApplicationUserRole 中再添加一个属性 'companyId' ,但我被困在覆盖 AddToRole 或 IsInRole 这些函数中。这些函数不接受 companyId。我正在尝试覆盖这些函数以获取图片中的 companyId。我已经在 [这里](stackoverflow.com/questions/29071800/…) 发布了我的问题。如果你能帮忙,那就太好了!谢谢
【解决方案2】:

我正在处理一个大型多租户应用程序。我们得出的结论是,为每个租户维护单独的数据库更容易,并让 Web 应用程序自动切换数据库上下文,而不是尝试使用过于复杂的数据库模式来为不同的租户建模。

好处

  1. 租户数据默认划分到不同的数据库中
  2. 租户数据可以导出为客户端 MI 的数据库转储
  3. 大大简化了数据库设计

缺点

  1. 您必须管理多个数据库 - 运营挑战
  2. 你必须开发数据库切换代码

使用多个数据库实现

  1. 我们使用了一个配置数据库,该数据库具有基于帐户代码的客户端设置。该帐户代码可以来自登录屏幕,也可以将子域映射到客户端代码。
  2. 当应用启动时,您将所有租户加载到缓存中(包含连接字符串)
  3. 对于每个请求,您必须确定客户端,然后切换数据库上下文

我还开发了一个使用单个数据库的多租户应用程序。您很快就会遇到确保不跨租户数据的问题。每个查询都需要包含一个租户 ID 过滤器。因此,数据库查询总是会变慢,尽管您可以索引所有内容以尝试改善情况。

关于会员问题,您可以将会员模式安装到每个租户数据库中。

什么不起作用

理想的替代方案是dynamically switch the ApplicationName,但尽管ApplicationName is not thread safe 似乎可行,因此这并不可靠:

因为一个默认的成员资格提供程序实例用于所有 由 HttpApplication 对象服务的请求中,您可以拥有 多个请求同时执行并尝试设置 应用程序名称属性值。 ApplicationName 属性不是 线程安全的多次写入,并更改 ApplicationName 属性值可能会导致多个用户的意外行为 一个应用程序。我们建议您避免编写允许 用户设置 ApplicationName 属性,除非您必须。一个例子 设置 ApplicationName 属性的应用程序的 required 是管理会员数据的管理应用程序 用于多种应用。这样的应用程序应该是单用户的 应用程序而不是 Web 应用程序。

替代方案:MembershipReboot

.Net 中的多租户很难。使用内置成员资格的开源替代方案是使用MembershipReboot,由Brock Allen 编写。它具有一些出色的功能,包括开箱即用的多租户支持:

  1. 单租户或多租户帐户管理
  2. 灵活的帐户存储设计(关系/SQL 或对象/NoSql),同时使用 EF 和 RavenDB 的示例
  3. 声明感知用户身份
  4. 支持账号注册、邮箱验证、密码重置等
  5. 多次失败登录尝试(密码猜测)导致帐户锁定
  6. 电子邮件通知的可扩展模板
  7. 可自定义的用户名、密码和电子邮件验证
  8. 帐户活动和更新通知系统(例如用于审计)
  9. 与外部身份提供商(企业或社交)关联的帐户
  10. 支持基于证书的身份验证
  11. 正确的密码存储(通过 PBKDF2)
  12. 可配置的迭代
  13. 默认为迭代的 OWASP 建议(例如 2012 年的 64K)
  14. 通过手机短信或客户端证书支持双重身份验证

最常见的用例是将其集成到 ASP.NET 或 ASP.NET MVC 应用程序,尽管该库也可以通过 网络即服务。

替代方案:ServiceStack REST

如果您正在构建大量使用 JavaScript MVC 框架(如 AngularJS、EmberJS 或 BackboneJS)的现代 Web 应用程序,另一种选择是使用 ServiceStack REST 服务。 ServiceStack 有一个long list of Authentication features,根据我对 SS 的经验,我发现它有一个经过深思熟虑的 API 模型。

【讨论】:

  • 这是否意味着 OP 的用户 Bob 必须创建 2 个用户帐户,一个用于 A 公司,另一个用于 B 公司?
  • 正确。但是为什么 A 公司的用户 A 会访问 B 公司的信息呢?
  • 这看起来像是 OP 中的要求:“我们有管理多个租户的代理,并希望能够使用单个用户帐户管理所有租户”我认为不要误会我的意思在某些多租户情况下,这是一个很好的解决方案。
  • 我们每个租户都有单独的数据库和配置数据库。成员资格数据在配置数据库中。
  • @TedElliott 我们也使用单个配置数据库,但这只是确定租户数据库连接字符串。您如何划分配置数据库中的租户用户?
猜你喜欢
  • 1970-01-01
  • 2015-03-06
  • 2011-05-05
  • 1970-01-01
  • 2017-03-13
  • 2018-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多