让我们说我正在使用rolify
宝石。 rolify gem处理用户可以在资源实例或资源类上拥有的权限。这很简单。如果需要确定用户是否可以执行某项任务,则会产生类似于此的内容:
if user.has_role? :admin
@article.update(article_params)
else
fail # just as an example
end
但是,我希望能够在范围上应用这些权限,例如Article.all
- 具体来说,我希望能够确定用户可以阅读哪些文章。假设只有角色为:admin
的用户才能阅读文章,我将如何进行此操作?
编辑:我面临的问题是这个。在运行时,我不知道任何给定用户可以阅读哪些文章。该信息存储在数据库中。因此,使用像cancancan或pundit这样的解决方案不会 - 也不能 - 在这种情况下帮助(注意:我实际上使用的是权威)。基本上,我必须弄清楚如何实现Pundit的Scope
类。
在我找到rolify
宝石之前,我向朋友提出了这样的问题:
所以我为了解决它而做的是:每个用户都有一组组;权限可以在用户或组上定义(两者都有效)。权限影响一组通用记录(我只存储记录类型,没有ID),特定记录(记录类型和ID),或作为整体记录(记录类型,没有ID,带有全局标记) )。权限也可以被否定,有效地删除用户对主题的任何权限。所以我的数据库看起来像这样:
Permissions id: Integer actor_id: Integer actor_type: String subject_id: Integer subject_type: String action: String negated: Boolean global: Boolean precedence: Integer Users id: Integer Groups id: Integer Articles id: Integer
我收录的文章有助于展示我尝试做的事情。因此,如果我应用这些权限:
Permission.create(actor: Group.find(1), subject: Article.find(1), action: "show") Permission.create(actor: Group.find(1), subject_type: "Article", action: "show") Permission.create(actor: User.find(1), subject: Article.find(1), action: "show", negated: true, precedence: 1)
当我去
permission_scope(Article, User.find(1))
时,我应该得到这个:[#<Article id=2>, #<Article id=3>, ...]
问题是,我不知道
permission_scope
的内容是什么,所以我不知道如何制作它。
答案 0 :(得分:1)
这些是适用于Rolify的Pundit自述文件的基本政策示例。
对于您只需要检查用户角色的简单情况:
class PostPolicy < ApplicationPolicy
class Scope
attr_reader :user, :scope
def initialize(user, scope)
@user = user
@scope = scope
end
def resolve
if user.has_role?(:admin)
scope.all
else
scope.where(:published => true)
end
end
end
def update?
user.has_role?(:admin) or not post.published?
end
end
如果您有资源范围的角色,则可以使用scopes provided by Rolify:
class PostPolicy < ApplicationPolicy
class Scope
attr_reader :user, :scope
def initialize(user, scope)
@user = user
@scope = scope
end
def resolve
Post.with_role(:author, user)
# or
Post.with_all_roles([:author, :editor], user)
end
end
def update?
user.has_role?(:author, post)
end
end
要使用权限系统执行相同的范围设定,您需要以下内容:
user = User.joins(:permissions, groups: [:permissions]).find(1)
article_ids = Permission.where(
actor_id: [user.id] + groups.ids,
subject_type: 'Article',
action: :show
).pluck(:subject_id)
Article.where(id: article_ids)
答案 1 :(得分:0)
根据您的更新,您肯定希望这个逻辑在一个单独的类中,并且由于感知复杂性,可能在不同的模块中。如果这是在任何开源的东西让我知道,因为看到它在使用将有助于更多。这不是一个容易的问题,但希望这会让你更接近。
module Scope
class Permission < Struct.new(:relation, :entity, :action)
def call
relation.merge(::Query::Permission.new(:relation, :entity, :action)
end
end
end
module Query
class Permission < Struct.new(:relation, :entity, :action)
def call
#Here is where you implement the logic to find records related to a relation/entity/action
end
end
end
所以现在你有了一些需要处理范围的东西以及一些可以搜索你的权限的东西来找到正确的记录。