【发布时间】:2012-06-17 19:02:35
【问题描述】:
我正在使用 Ruby on Rails 3.2.2,我想知道当必须检查用户是否具有适当的权限来“读取”记录“列表”中存在的记录时,常用方法是什么。也就是此时我有以下:
class Article < ActiveRecord::Base
def readable_by_user?(user)
# Implementation of multiple authorization checks that are not easy to
# translate into an SQL query (at database level, it executes a bunch of
# "separate" / "different" SQL queries).
... # return 'true' or 'false'
end
end
通过使用上述代码,我可以对单个文章对象执行授权检查:
@article.readable_by_user?(@current_user)
但是,当我想(通常在我的控制器 index 操作中)通过准确检索 10 个对象来制作类似以下内容时
Article.readable_by_user(@current_user).search(...).paginate(..., :per_page => 10)
我仍然必须对每个对象执行授权检查。所以,我可以做些什么来对记录“列表”执行授权检查(Article 对象数组)在“智能" / "performant" 方式?也就是说,例如,我应该加载Article.all(可能按创建的数据排序,将 SQL 查询限制为 10 条记录,...)然后迭代每个对象以便执行授权检查?还是我应该做一些不同的事情(可能使用一些 SQL 查询技巧、一些 Ruby on Rails 工具或其他东西)?
@Matzi 回答后更新
我尝试由用户“手动”检索文章可读,例如使用find_each 方法:
# Note: This method is intended to be used as a "scope" method
#
# Article.readable_by_user(@current_user).search(...).paginate(..., :per_page => 10)
#
def self.readable_by_user(user, n = 10)
readable_article_ids = []
Article.find_each(:batch_size => 1000) do |article|
readable_article_ids << article.id if article.readable_by_user?(user)
# Breaks the block when 10 articles have passed the readable authorization
# check.
break if readable_article_ids.size == n
end
where("articles.id IN (?)", readable_article_ids)
end
此时,上面的代码是我能想到的最“性能妥协”,即使它有一些陷阱:它“限制”检索到的对象数量为给定数量给定ids 的记录数(上例中默认为 10 条记录);实际上,它“真的”不会检索用户可读的所有对象,因为当您尝试进一步确定相关 ActiveRecord::Relation "where" / "with which" 的范围时,readable_by_user 范围方法被使用(例如,当您还通过 title 添加进一步的 SQL 查询子句来搜索文章时),它会将记录 限制 到那些 where("articles.id IN (?)", readable_article_ids) (即,它“限制”/“将检索到的和可读的对象的数量限制为前 10 个,并且用户在通过title 搜索时将忽略所有其他文章可读)。为了使readable_by_user 方法与其他范围方法一起正常工作,解决该问题的方法可能是not break 块以便加载所有可读文章,但是当有很多记录时,出于性能原因(也许,另一种解决方案可能是将用户可读的所有文章ids 存储在某处,但我认为这不是一个常见/简单的解决方案解决问题)。
那么,有一些方法可以以一种高效且“真正”正确的方式完成我想做的事情(也许,通过改变上述方法)?强>
【问题讨论】:
-
我们可以得到
readable_by_user?的完整代码吗? -
@patrickmcgraw - 出于“隐私政策”的原因,我无权发布
readable_by_user?方法的完整代码。我可以说,在数据库级别,它执行一堆“单独”/“不同”的 SQL 查询。 -
好的,我只是想问问。我很难思考如何拥有一组无法通过 SQL 关联的表。特别是当 SQL 已经单独处理表以达到预期目的时。是否有任何
readable_by_user?检查完全依赖于数据库之外的东西,例如应用程序状态? -
@patrickmcgraw - 感谢您对“隐私政策”的理解。我的回答是:不,
readable_by_user?检查确实不完全依赖于数据库之外的东西。 -
通过数据库逻辑授权是一种高效的方法。您可以用通用术语描述您的授权逻辑。它将帮助社区回答您的问题。
标签: ruby-on-rails ruby-on-rails-3 performance activerecord authorization