如何在不使用子域的情况下设置多租户Rails应用?

时间:2019-02-13 17:58:34

标签: ruby-on-rails ruby authorization multi-tenant pundit

我正在尝试创建一个具有供员工使用的后端的SAAS电子商务工具,该工具还允许客户在前端进行帐户和结帐。我正在努力设计该方法,以便使公司,帐户所有者,员工和客户都与每个公司隔离,同时还要根据角色对其进行适当的限制。

据我到目前为止所读的内容,大多数Rails解决方案都使用带有子域(例如Apartment gem)的多租户模式来隔离帐户。但是,让您的网站使用一个大型应用程序和数据库似乎更简单。例如,Basecamp最近使用Basecamp3切换到此方法。较新的应用似乎是通过这种方式构建的。

并且,管理功能和客户帐户/前端商店应该是完全独立的应用程序,还是可以使用“ majestic monolith”来实现?一个大的应用程序和数据库虽然很大,但对我来说似乎更简单。

我发现this blog post解释了如何使用Pundit做类似的事情,但是我仍然很难理解如何与帐户所有者,员工和客户一起使用在同一应用中。

这是我的应用程序的基本需求:

用户角色

  • 帐户所有者(创建公司帐户并拥有对其公司数据的完全访问权限)
  • 工作人员(受邀加入公司,但无权访问公司的某些数据,例如账单信息)
  • 客户(可以注册该网站并查看产品,将其添加到购物车,但不能使用任何员工或帐户所有者功能。)
  • 所有用户(无论角色如何)都属于公司,并且无法访问其他公司的数据。 (因此,可以在同一应用程序上运行单独的商店,这是将其作为SAAS应用程序运行所必需的。)
  • 帐户所有者和员工可以CRUD产品,但不能CREW客户。

一个很好的类比是Shopify的管理区域和客户帐户当前如何用于商店所有者,但是与Shopify不同,它不需要使用子域。

潜在模型和关联

Company
has_many :users, dependent: :destroy
has_many :products, dependent: :destroy

User
belongs_to :company

Product
belongs_to :company

授权

  • 使用Pundit来限制基于用户角色的控制器操作,然后确保通过模型关联隔离数据是否可行?

注册流程

对于如何处理不同的用户角色以及“工作人员邀请”和“客户”注册的位置可能适合注册流程,我有点模糊。

这种方法行得通吗?

  1. 为“帐户所有者注册”,“工作人员注册”,“客户注册”创建单独的控制器,然后将我的注册表单嵌入到这些视图中。 (使用Clearance进行身份验证,并尽可能保留该身份,但仅在需要时进行扩展)。
  2. 帐户所有者注册:因此,如果某人通过“新帐户注册”控制器(带有嵌入式身份验证表单)进行注册,他们还将创建公司。
  3. 员工邀请:帐户所有者可以通过输入姓名和电子邮件地址来创建新的员工用户。这将创建一个具有“工作人员”角色的新用户(因此不能成为另一个帐户的帐户所有者)。将向新的“ Staff”用户发送邀请电子邮件,该电子邮件基本上是密码重置电子邮件,通过创建密码来邀请他们接受邀请。
  4. 客户注册:如果某人通过“客户注册”控制器注册,他们将自动获得用户角色“客户”。在这种情况下,不确定如何设置公司ID。 (将company_id作为隐藏输入传递给客户注册表单?)

是否有更好的方法来设计我所缺少的这种类型的应用程序?我在正确的轨道上吗?我没有建立类似这样的经验,因此任何线索都将非常有帮助。

似乎新的应用程序遵循这种类型的模式进行多租户而非子域访问。

1 个答案:

答案 0 :(得分:2)

您以simple e-commerce site开头,但您所提出的问题表明您正在寻找更复杂的东西:)您的方向正确。

acts_as_tenant宝石值得一看。我们现在使用它,它有助于确保所有查询的范围都适当。

如果您需要扮演角色,我也会查看并评估rolify(但也不要排除用户上的布尔标志)。

我不排除设计,但许可很受欢迎。

根据工作量的不同,使用子域可能是未实现的工作,除非您出于虚荣的目的实际使用子域(my.example.com与example.com/my),否则可以进行多租户。

如果他们的访问权限千差万别,我会考虑为不同的角色使用单独的控制器和命名空间;您还可以使用Pundit将它们组合为单个控制器(但这可能很笨拙)。您仍然需要使用Pundit,但是,Pundit可以执行诸如确定用户应查看的记录范围之类的事情。

您走在正确的道路上并提出了正确的问题,但是所有这些问题的答案将取决于其他问题(您现在可能甚至无法回答)。

我有一个项目正在按照您的指示进行(专为限制数据,acts_as_tenant为孤岛事务),但是随着项目的发展,出现了某些模式,这些模式导致我走了一条不同的道路。例如,命名空间管理员,而不是在同一个控制器内进行管理员检查;因为如果您重写API,最终将试图使同一个终结点做不同的事情,并且将命名空间后面的两个终结点分开并记录我的实际行为会更清洁。