【发布时间】:2023-10-22 04:53:01
【问题描述】:
我正在尝试测试Farm 模型的用户身份验证,在这种情况下,:user 角色在登录时具有对所有场的读取访问权限(作为访客user aka.anonymous 也有)。
# /models/ability.rb
class Ability
include CanCan::Ability
def initialize(user)
# Create guest user aka. anonymous (not logged in) when user is nil.
user ||= User.new
if user.has_role? :admin
can :manage, :all
else # guest user aka. anonymous
can :read, :all
# logged in user
if user.has_role? :user
can :create, Farm
can :manage, Farm, :user_id => user.id
end
end
end
end
...
# /controllers/api/v1/farms_controller.rb
class Api::V1::FarmsController < ActionController::Base
load_and_authorize_resource
rescue_from CanCan::AccessDenied do |exception|
redirect_to farms_path, alert: exception.message
end
respond_to :json
def index
# Next line might be redundant refering to the CanCan wiki. See below..
@farms = Farm.accessible_by(current_ability, :read)
respond_with(@farms)
end
end
...
# /spec/api/v1/farm_spec.rb
require "spec_helper"
describe "/api/v1/farms" do
let(:user) { create(:user) } # lets call this user1 in the discussion
let(:token) { user.authentication_token }
before do
user.add_role :user
create(:farm, user: user, name: "Testfarm")
create(:farm, name: "Access denied")
@ability = Ability.new(user)
end
context "farms viewable by this logged-in user" do
let(:url) { "/api/v1/farms" }
it "json" do
get "#{url}.json"
farms_json = Farm.accessible_by(@ability, :read).to_json
assert last_response.ok?
last_response.body.should eql(farms_json)
last_response.status.should eql(200)
farms = JSON.parse(last_response.body)
farms.any? do |farm|
farm["name"] == "Testfarm"
end.should be_true
farms.any? do |farm|
farm["name"] == "Access denied"
end.should be_true
end
end
end
问题
当我检查 farms_json 时,我可以看到它只包含 Testfarm。当我检查last_response 时,我可以看到它包含both Testfarm 和 Access denied。这很奇怪,因为我在规范和 index 操作中都使用了相同的 accessible_by 方法。我使用的设置在名为 Fetching Records 的 CanCan gem 的 wiki 中进行了描述。
无用的解决方法
当我将用户user添加到农场Access denied时,比如...
create(:farm, user: user, name: "Access denied")
...那么测试成功。
问题
- 为什么任何用户(包括来宾用户)都可以读取“访问被拒绝”场不返回?
-
get "#{url}.json"真的会考虑用户的状态吗?这一切都是由FarmsController中的load_and_authorize_resource完成的吗? -
wiki mentions 和
@farms = Farm.accessible_by(current_ability, :read)可以省略,因为“这是由load_resource为索引操作自动完成的”。这适用于我的情况吗?
实验
我创建了另一个用户“user2”和另一个农场“我的小农场”。我把它们联系起来了。这样,示例中的数据库总共包含三个农场:
- 与 user1 关联的农场“Testfarm”
- 农场“拒绝访问”与任何用户关联
- 与 user2 关联的农场“我的小农场”。
当我运行Farm.accessible_by(Ability.new(user1), :read) 时,我仍然只收到“Testfarm”。
【问题讨论】:
标签: ruby-on-rails ruby-on-rails-3 rspec cancan rolify