多租户网络应用程序:在Devise中设计?

时间:2015-12-27 01:10:36

标签: ruby-on-rails postgresql devise multi-tenant

我正在尝试构建一个多租户应用,用户可以拥有自己的网站,在该网站中,访问者可以创建帐户和登录等。

我将在这个应用程序中使用Postgresql架构。

现在,用户可以创建基本网站,添加内容等。但我希望访问者能够在这些网站中注册帐户。

例如,用户创建网站site.app.com 他可以登录site.app.com/admin来管理他的网站。 现在我希望访问者能够在site.app.com中创建一个帐户(当然会存储该帐户以及该网站的架构),登录和注销等。

这让人感到困惑,如果有人做过这样的事情,请帮助我实现这个目标。

由于

2 个答案:

答案 0 :(得分:0)

有几种方法可以做到这一点。如果您在某人访问特定页面或登录到特定上下文时使用模式并切换应用程序的范围,那么您应该只需要这样做。

大多数人只需在用户上方添加模型(如帐户),然后在有人刚刚注册到您的网站时创建帐户,然后将用户与account_id关联为外键时即可实现此目的。之后,您将应用中的活动范围限定为适当的帐户,其他所有内容都相同。这是你如何用设计做到的。以下是如何在RegistrationsController中进行设计的示例。

http://www.austinstory.com/category/programming/rubyonrails/devise/

答案 1 :(得分:0)

我以前做过这样的事情。

我需要解释一下......

标准意义上的

Multi Tenancy表示为单个应用程序使用多个环境。正如explained

  

软件多租户是指中的软件架构,其中a   单个软件实例在服务器上运行并提供多个服务   租户即可。租户是与用户共享共享访问权限的一组用户   软件实例的特定权限。有多租户   体系结构,软件应用程序旨在提供每一个   租户是该实例的专用共享,包括其数据,   配置,用户管理,租户个人功能和   非功能性。多租户与多实例形成鲜明对比   架构,其中单独的软件实例代表   不同的租户。

简而言之,这意味着真正的多租户应用程序应该能够使用相同的资源为许多不同的用户提供服务。就Rails而言,这非常简单,因为它都建立在HTTP上 - stateless protocol

真实"云"应用程序(我们还没有看到)必须是有状态的 - 非常类似于利用数据中心的计算能力的本机应用程序。一个很好的例子就是那些将所有数据存储在服务器上的RPG游戏。

-

虽然Rails自然是多租户,但它的数据库不是。

How to create a multi-tenant database with shared table structures?

在我的脑海里 - 也许我'"错误" - 真正的多租户应用程序应为每个用户分配一个单独的数据库,共享一个中央数据库,例如" accounts"等:

-- database
  -- accounts
  -- invoices
  -- users
   -- 1
     -- pictures
     -- users
     -- etc
   -- 2
     -- pictures
     -- users
     -- etc

这可能看起来很复杂,但是如果你正确对待它,它将使你能够安全地存储每个用户的数据等。

关于您的应用程序,这意味着您将所有数据存储在单个数据库中,并链接到单个应用程序。

这意味着您可以使用sessionsroles创建用户身份验证结构:

  • 每个"子域名"仅存储该子域的会话
  • 每个"子域名" (帐户)对分配给该帐户的用户进行验证
  • 每个用户都将分配参与该帐户的角色

简单实施模型:

#app/models/account.rb
class Account < ActiveRecord::Base
   # This is for the "site" -- will create the subdomain etc
   has_many :memberships
   has_many :users, through: :memberships
end

#app/models/membership.rb
class Membership < ActiveRecord::Base
   belongs_to :account
   belongs_to :user
   belongs_to :role
end

#app/models/user.rb
class User < ActiveRecord::Base
   has_many :memberships
   has_many :accounts, thorugh: :memberships
end

#app/models/role.rb
class Role < ActiveRecord::Base
   has_many :memberships
end

这将允许您创建帐户,将用户分配给这些帐户,并将不同的信息存储在成员资格模型中(例如角色)等)。

-

这将为您提供多租户应用程序的主要功能(能够拥有&#34;帐户&#34;,为这些帐户自定义环境,然后拥有该特定帐户的成员)。

您可以执行各种其他操作,但之后的主要内容是会话(因此用户只能登录到单个子域):

Share session (cookies) between subdomains in Rails?

默认处理;如果你想&#34;分享&#34;子域名之间的会话,您必须将tld_length: 2添加到session_store.rb

-

要处理子域just set it up in the routes(就像Ryan Bates用他的Railscast做的那样):

#config/routes.rb
scope constraints: AccountManager do

    #This is from an app we're working on..... put what you want here.

    #Users
    devise_for :users, path: "", controllers: { sessions: "auth/sessions" }, path_names: { sign_in: "login", password: "forgot", confirmation: "confirm", unlock: "unblock", sign_up: "", invitation: "add", accept: "", registration: "register", sign_out: "logout" }

    #Authentication
    authenticate :user do
      root "transactions#index", as: :authenticated
    end

    #Core
    authenticated :user do
      resource  :settings, controller: :users, only: [:show, :update], constraints: { format: :js }         # User profile & settings (doubles up as options editor)
      resources :transactions, path: "", only: [:index, :update, :destroy], constraints: { format: :js } do # CRUD transactions
        scope format: true do #-> for constraints
          get :new, on: :new, constraints: { format: :js }
        end
        match "search(/:query)", action: :search, as: :search, on: :collection, via: [:get, :post]
      end
    end

end

#lib/account_manager.rb
module AccountManager

    # Refs
    # https://viget.com/extend/using-routing-constraints-to-root-your-app
    # https://stackoverflow.com/questions/5192175/how-to-set-in-a-middleware-a-variable-accessible-in-all-my-application

    def initializer(router)
        @router = router
    end

    def self.matches?(request)
        Account.exists? request.subdomain
    end

end

这将允许您登录等(您必须修改Devise才能仅接受帐户的members)。

最后,要获得&#34; admin&#34;部分工作,你最好创建一个&#34; / admin&#34;您的子域中的路径,只允许管理员角色访问:

#config/routes.rb
scope constraint: AccountManager do
   namespace :admin do #-> account.app.com/admin
      # stuff here
   end
end

这将允许您在管理员控制器中使用基本授权:

#app/controllers/admin/application_controller.rb
class Admin::ApplicationController < ActionController::Base
   before_action :is_admin?

   private

   def is_admin?
      redirect_to root_path, notice: "Admin Only" unless current_user.admin? #-> has to check membership if is admin
   end
end

您还可以在app.com/admins上创建单独的管理界面;你只能让管理员登录等等。