【问题标题】:Rails Company-specific user permissions with Pundit使用 Pundit 的 Rails 公司特定用户权限
【发布时间】:2019-08-27 05:25:20
【问题描述】:

我实际上不确定这是 Pundit 还是一般权限架构问题,但我设置了一个简单的 Pundit 策略来限制公司内成员可以执行的操作。用户作为成员以has_many, through: 关系加入公司。 Member 模型的role 属性为owneruser

给定一个用户是商店的成员,我如何限制控制器中的访问权限,以便用户与商店的关联?下面是Admin::MembersController,店主可以邀请其他成员。如何通过他们与商店的成员关联将其限制为权威人士中的给定用户?下面的策略不起作用,返回一个记录数组。如果我只检查第一条记录,它会起作用,但我觉得这是因为我的理解有限。

我在网上看到的 CCC 和 Pundit 的所有教程和文档 涉及应用程序范围的权限。但我需要更细化 控制。

例如,我的应用程序有数百家公司。每个公司 有一个用户是“所有者”,他们每天登录查看他们的 收益信息。该所有者/用户想要邀请 Joe Smith 加入 应用程序,以便他们还可以查看数据并进行更改。但 他们不希望 Joe Smith 能够看到某些类型的数据。所以 我们限制 Joe Smith 访问该公司的某些数据。

class Admin::MembersController < Admin::BaseController

  def index
    @company_members = current_company.members
    authorize([:admin, @company_members])
  end
end

政策

class Admin::MemberPolicy < ApplicationPolicy

  def index?
    return [ record.user_id, record.store_id ].include? user.id
    ## this works return [ record.first.user_id, record.first.store_id ].include? user.id
  end
end

用户.rb

class User < ApplicationRecord
  # Automatically remove the associated `members` join records
  has_many :members, dependent: :destroy
  has_many :stores, through: :members
end

会员.rb

class Member < ApplicationRecord
  belongs_to :store
  belongs_to :user

  enum role: [ :owner, :user ]
end

Store.rb

class Store < ApplicationRecord
  has_many :members
  has_many :users, through: :members
end

【问题讨论】:

  • 您能解释一下限制访问关联是什么意思吗?据我了解,您可能希望根据角色运行不同的查询,以向用户隐藏某些数据,但向所有者显示
  • @AsimHashmi 正是你提到的。定义owner 的属性是成员模型(这是一个连接模型)上的role,并导致与 Pundit 混淆

标签: ruby-on-rails pundit


【解决方案1】:

我从 Pundit 的贡献者那里得到了一些见解;最合理的解决方法是使用表示用户所在上下文的域对象 - 自述文件 (https://github.com/varvet/pundit#additional-context) 中有关于此的信息。 UserContext 对象将提供对用户和组织的引用。

class ApplicationController
  include Pundit

  def pundit_user
    if session[:organization_id]
      UserContext.new(current_user, Organization.find(session[:organization_id]))
    else
      UserContext.new(current_user)
    end
  end
end

class UserContext
  attr_reader :user, :organization

  def initialize(user, organization = nil)
    @user           = user
    @organization   = organization
  end
end

【讨论】:

    【解决方案2】:

    我认为您正在寻找的是权威人士的范围。您希望限制对商店成员的某些数据访问,并将该数据显示给该商店的所有者。

    为此,您需要根据用户角色更改查询

    类似这样的:

    class EarningPolicy < ApplicationPolicy
      class Scope
        attr_reader :user, :scope
    
        def initialize(user, scope)
          @user  = user
          @scope = scope
        end
    
        def resolve
          # here check for owner and show all data
          if user.members.owner # here you query your memberships to find the owner role.
            scope.all
          else
            # here show only data relevant to member
            scope.where(published: true)
          end
        end
      end
    end
    

    您现在可以在控制器中像这样使用此类

    def index
      @earnings = earning_scope(Earning)
    end
    

    希望对你有帮助

    【讨论】:

    • 感谢@AsimHashmi 的回复。这是一个好的开始。但是角色属性不在用户身上——它在加入的会员模型上,一个用户可以拥有许多成员资格。我不确定如何深入访问当前用户的成员资格。在 CanCan 中,您可以传递第三个参数,例如 store_id
    • @VegaStudios 您可以查询您的用户模型以查找所有者成员资格,如果它不存在,那么您可以限制向用户显示的数据。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-08
    • 1970-01-01
    • 1970-01-01
    • 2017-11-03
    • 2021-08-06
    • 1970-01-01
    相关资源
    最近更新 更多