我有一个系统,其中User
可以与许多Portals
相关联,但用户的权限可能会因门户网站而异。
例如,用户可能能够在一个门户中看到未发布的帖子,但在另一个门户中却看不到。
对于像show?
这样的方法,我可以抓住记录中的门户网站。
def show?
portal = record.portal
# logic to check whether, for this particular portal,
# this user has permission to view this record
end
但是,该解决方案不适用于策略范围。
有没有办法可以把门户网站传递给控制器中的policy_scope
方法?
我在这个地方看到的一个解决方案是为用户设置(临时)属性,以便策略方法可以使用它。 e.g。
# model
class User < ActiveRecord::Base
attr_accessor :current_portal
...
end
# controller
posts = portal.posts
current_user.current_portal = current_portal
policy_scope posts
# policy Scope
def resolve
portal = user.current_portal
# logic to scope these records by user's portal permissions
end
然而,这似乎是一种解决方法,我绝对可以想到其他情况,我希望能够为授权逻辑提供更多的上下文,我不希望这种解决方法成为一个坏习惯。
有没有人有任何建议?
答案 0 :(得分:0)
Pundit授权类是普通的旧ruby类。使用pundit authorize
方法,您可以传递要授权的对象和可选查询。例如,当您使用授权方法
authorize @product, :update?
authorize方法将调用update?
类上的ProductPolicy
方法。如果没有传递查询,控制器动作名称+?标记将被设置为查询。看看Pundit authorize method definition。
因此,为了将额外的参数传递给Pundit授权方法,您应该使用额外的参数覆盖authorize方法:
module Pundit
def authorize(record, query=nil, options=nil)
query ||= params[:action].to_s + "?"
@_pundit_policy_authorized = true
policy = policy(record)
if options.nil?
raise NotAuthorizedError, query: query, record: record, policy: policy unless policy.public_send(query)
else
raise NotAuthorizedError, query: query, record: record, policy: policy unless policy.public_send(query, options)
end
end
end
然后在您的策略类中,您可以使用此额外参数
class ProductPolicy
...
def update?(options)
...
end
def new?
...
end
...
end
如您所见,您可以使用接受额外选项参数的策略方法。
然后,您可以通过以下方式之一在控制器中使用authorize方法:
authorize @product
authorize @product, nil, { owner: User.find(1) }
authorize @product, :some_method?, { owner: User.find(1) }
authorize @product, :some_method?