首页 文章

多租户应用程序中的授权

提问于
浏览
1

在Railscasts Episode 388 - Multitenancy with Scopes中,Ryan正在添加默认范围以确保安全性:

或者,我们可以使用CanCan等授权库来处理范围,但这不适用于多租户应用程序,并且不能很好地解决这个问题 . 这是一种可以使用默认范围的情况,这就是我们要做的事情 .

class Tenant < ActiveRecord::Base
  attr_accessible :name, :subdomain
  has_many :topics
end

class Topic < ActiveRecord::Base
  attr_accessible :name, :content
  belongs_to :user
  has_many :posts

  default_scope { where(tenant_id: Tenant.current_id) }
end

我的问题是:我想实现授权(例如使用Cancan)并且想要定义这样的能力:

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new # guest user (not logged in)
    if user.admin?
      can :manage, Topic
    else
      can :read, Topic
    end
  end
end

用户是否有能力管理所有租户的主题或仅在租户范围内?

或者是一个更普遍的问题:多租户应用程序的授权方法是什么?

3 回答

  • 2

    我认为,由于CanCan已被弃用,因此您使用CanCan或CanCanCan是正确的 .

    我不喜欢 default_scope ,因为它不是threadsafe . 用户标识存储在类变量中,这意味着应用程序中的两个或多个并发用户将断开此操作,除非您使用Unicorn或其他一些确保不超过一个客户端连接将访问同一线程的Web服务器 .

    因此你应该使用像Cancan这样的东西 .

    class Ability
      include CanCan::Ability
    
      def initialize(user)
        user ||= User.new # guest user (not logged in)
        if user.admin?
          # User's own Topics only:
          can :manage, Topic, user_id: user.id
          # or, with a Tenant
          can :manage, Topic, tenant_id: user.tenant.id if user.tenant # User belongs_to Tenant
          can :manage, Topic, tenant_id: user.tenants.map(&:id) if user.tenants.any? # User has_many Tenants
        else
          can :read, Topic # Anyone can read any topic.
        end
      end
    end
    

    从上面的三个示例中选择您需要的策略 .


    EDIT 多个租户管理员对于@ JoshDoody在评论中的问题稍微复杂一些的例子:


    class Admin < User; end
    
    class TenantAdmin
      belongs_to :tenant
      belongs_to :admin, class_name: User
    end
    
    class Ability
      include CanCan::Ability
    
      def initialize(user)
        user ||= User.new # guest user (not logged in)
        if user.admin?
          can :manage, Topic, tenant_id: TenantAdmin.where(admin: user).map(&:tenant_id)
        else
          can :read, Topic # Anyone can read any topic
        end
      end
    end
    

    现在,这可能不是您想要的高效,但总的想法是您有TenantAdmins,他们将能够在他们的租户中管理主题 .

    希望这可以帮助 .

  • 1

    你已经为Topic设置了能力 . 因此,它只会检查主题对象 .

    要检查租户级别,您需要设置如下内容:

    class Ability
      include CanCan::Ability
    
      def initialize(user)
        user ||= User.new # guest user (not logged in)
        can :manage, Tenant do |tenant|
          if user.admin?
            `you code goes here`
          else
          end
        end
        can :read, Tenant
        can :read, Topic
      end
    end
    
  • 4

    Мie多功能应用程序的能力的例子

    class Ability
      def initialize(admin,  tenant = nil)
         user ||= User.new
         if user.admin?
           can :manage, Topic
         else
           can :manage, PostState, tenant: tenant
         end
      end
    end
    

    您可能无法通过租户并使用 Tenant.current_id

相关问题