Rails Pundit 的公司特定用户权限
Rails Company-specific user permissions with Pundit
我实际上不确定这是 Pundit 还是一般权限架构问题,但我设置了一个简单的 Pundit 策略来限制公司内成员可以执行的操作。用户以 has_many, through:
关系作为会员加入公司。 Member 模型的 role
属性为 owner
或 user
.
给定一个用户是商店的成员,我如何限制控制器对用户与商店的关联的访问?下面是一个Admin::MembersController
,店主可以在其中邀请其他成员。我如何通过他们与商店的会员协会将此限制为专家中的给定用户?下面的策略不起作用,返回一个记录数组。如果我只检查第一条记录它有效但我觉得那是因为我的理解有限。
All of the tutorials and documentation I see online for CCC and Pundit
involve application-wide permissions. But I need more granular
control.
For example, my application has hundreds of companies. Each company
has a user who is an "owner" and they login each day to look at their
earnings information. That owner/user wants to invite Joe Smith to the
application so they can also look at the data and make changes. But
they don't want Joe Smith to be able to see certain types of data. So
we restrict Joe Smith's access to certain data for that company.
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
User.rb
class User < ApplicationRecord
# Automatically remove the associated `members` join records
has_many :members, dependent: :destroy
has_many :stores, through: :members
end
Member.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
我认为您正在寻找的是 pundit 中的范围。您希望将某些数据访问限制为商店成员,并将该数据显示给该商店的所有者。
为此,您需要根据用户角色更改查询
像这样:
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
您现在可以在控制器中像这样使用 class
def index
@earnings = earning_scope(Earning)
end
希望对您有所帮助
我从 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
我实际上不确定这是 Pundit 还是一般权限架构问题,但我设置了一个简单的 Pundit 策略来限制公司内成员可以执行的操作。用户以 has_many, through:
关系作为会员加入公司。 Member 模型的 role
属性为 owner
或 user
.
给定一个用户是商店的成员,我如何限制控制器对用户与商店的关联的访问?下面是一个Admin::MembersController
,店主可以在其中邀请其他成员。我如何通过他们与商店的会员协会将此限制为专家中的给定用户?下面的策略不起作用,返回一个记录数组。如果我只检查第一条记录它有效但我觉得那是因为我的理解有限。
All of the tutorials and documentation I see online for CCC and Pundit involve application-wide permissions. But I need more granular control.
For example, my application has hundreds of companies. Each company has a user who is an "owner" and they login each day to look at their earnings information. That owner/user wants to invite Joe Smith to the application so they can also look at the data and make changes. But they don't want Joe Smith to be able to see certain types of data. So we restrict Joe Smith's access to certain data for that company.
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
User.rb
class User < ApplicationRecord
# Automatically remove the associated `members` join records
has_many :members, dependent: :destroy
has_many :stores, through: :members
end
Member.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
我认为您正在寻找的是 pundit 中的范围。您希望将某些数据访问限制为商店成员,并将该数据显示给该商店的所有者。
为此,您需要根据用户角色更改查询
像这样:
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
您现在可以在控制器中像这样使用 class
def index
@earnings = earning_scope(Earning)
end
希望对您有所帮助
我从 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