Ruby on rails 基于订阅的rails查询限制
我有一个相当复杂的问题,我可以提供一些帮助,因为我尝试的所有实现都有缺陷(Rails 4.2.1) 用户可以访问以下设备:Ruby on rails 基于订阅的rails查询限制,ruby-on-rails,ruby-on-rails-4,Ruby On Rails,Ruby On Rails 4,我有一个相当复杂的问题,我可以提供一些帮助,因为我尝试的所有实现都有缺陷(Rails 4.2.1) 用户可以访问以下设备: create_table "devices", force: :cascade do |t| t.string "device_guid" t.datetime "created_at" t.datetime "updated_at" t.integer "user_ids" end 并且设备有许多数据条目: create_table "datas"
create_table "devices", force: :cascade do |t|
t.string "device_guid"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "user_ids"
end
并且设备有许多数据条目:
create_table "datas", force: :cascade do |t|
t.string "device_id"
t.datetime "start_time"
t.datetime "end_time"
end
我们希望将所有查询限制为基于订阅的数据
create_table "subscriptions", force: :cascade do |t|
t.integer "device_id"
t.integer "user_id"
t.datetime "start_date"
t.datetime "end_date"
end
因此,有效地说,除非订阅允许,否则不应该访问数据
我希望在一个地方完成这个限制(而不是通过单独的方法来访问它),所以其他编写代码的人仍然要处理订阅限制。我不想使用第三方gem,因为数据非常敏感
我认为最明显的方法是在数据模型上设置一个默认范围,但我遇到了几个问题:1)您无法从数据模型访问@user。我通过一个丑陋的黑客程序从模型中访问User.current解决了这个问题。
2)我不能使用当前用户,因为我们有冒充其他用户的管理员,需要查看数据。使用与#1相同的解决方法
3)同一用户和设备可以有多个日期不同的订阅。据我所知,没有任何方法可以执行ActiveRecord查询,该查询可以解释两个不同的日期范围(我使用arel_表解决了这个问题)。
4)这使得当我在rails控制台中时(理论上是通过API接口),所有查询数据的方法都会失败。如果没有User.current,我会忽略默认范围,但这显然是一个安全问题。
这是我当前的实现(在psuedocode中):
query=[]
订阅。每个do|
if(User.current.id==s.User\u id)
temp=Data.all.where(数据[:开始时间]>=s.start\u日期)。where(数据[:结束时间]datas.device\u id
可能应该是一个整数一个整数。不要在模型级别上进行授权。我不想在这里反复无常,但你真的认为你的自制解决方案会比像CanCan或Pundit这样经过战斗测试的授权解决方案更安全吗?闻起来像是“未发明”综合症。基本上,原因是关于不应该在模型级别执行此操作的原因,是模型不应该知道应用程序环境,例如会话。这会导致可怕的复杂代码。相反,您可以执行Pundit所做的操作,并使用策略类,该类接受要授权的模型或范围以及用户,并返回true/false(或引发异常)@max我知道这似乎不是在这里发明的,但我使用了大量的gems,这只是我们希望重写的特定于安全的gems。这就是我们正在设计的。我喜欢gems,使用了大量的gems,但这不是我的要求,我个人同意这一点,对于这个特定的案例,这些数据非常敏感。你能给我多一点信息吗回答中关于政策类的陈述?如果我选择了这条路线,我会选择它作为正确答案-谢谢你的建议。
query = []
Subscription.each do |s|
if (User.current.id == s.user_id)
temp = Data.all.where(data[:start_time] >= s.start_date).where(data[:end_time] <= s.end_date).where(data[:device_id] == Device.find_by(id: s.device_id).device_guid)
end
end
query += temp
end
default_scope { query }
<%= @user.device.find(1).data.all.count %>