CanCan Rails 如何限制用户读取非他们创建的数据
CanCan Rails How to Limit Users From Reading Data They Didn't Create
我在 Rails 3.2 应用程序中使用 CanCan 1.6.1。我在我的控制器中使用 authorize_resource
来限制用户可以 :read, :create, :update: and :delete
的内容。
在我的 V2Posts controller
中,authorize_resource
调用对我的 :show
操作无效。
在我的能力文件中,我试图限制用户只能阅读他们自己的帖子。没有错误,但不幸的是,他们可以查看其他用户的帖子。
class V2PostsController < ApplicationController
layout 'panel_layout', only: :show
before_filter :redirect_if_existing, only: [:new, :create]
authorize_resource
def show
@v2_post = V2Post.find(params[:id], include: :user_updates)
@organization = @v2_post.organization
respond_to do |format|
format.html
format.js
end
end
...
end
ability.rb:
class Ability
include CanCan::Ability
@user = nil
def initialize(user)
alias_action :taco,
:sandwich,
to: :read
@user = user
if user.is_in_role?(:admin)
can :manage, :all
else
default_rules
user.roles_list.each do |role|
meth = :"#{role}_rules"
send(meth) if respond_to? meth
end
end
end
def default_rules
cannot [:read, :create, :update, :destroy], :all
...
end
def pro_user_rules
can :read, V2Post, proid: @user.id
end
...
end
models/v2_post.rb:
class V2Post < ActiveRecord::Base
attr_accessible :proid, :user_updates_attributes, :organization
belongs_to :user, :foreign_key => "proid"
has_many :user_updates, as: :pro_post, dependent: :destroy
accepts_nested_attributes_for :user_updates
end
load_and_authorize_resource
用于阻止用户查看其他用户的帖子。但是,它会为我加载资源,还会为其他操作添加额外的数据库调用。 authorize_resource
不应该适用于我的情况吗?我已经在 show 动作中明确定义了 @v2_posts (我自己加载资源)。为什么它没有传递给 authorize_resource
调用?
- 我想避免额外调用数据库
- 我不想为自定义操作自动加载资源
- 我想授权每个 CRUD 操作。
鉴于此,load_and_authorize_resource
和 authorize_resource
哪个效果更好,每个 benefits/drawbacks 是多少?我已经阅读了文档,我很困惑。
问题是 authorize_resource
被 运行 用作前过滤器,并且直到在您的操作中 - 在调用 authorize_resource
之后才设置实例。当实例为nil时,authorize_resource
方法默认授权classV2Report
。授权 class 忽略属性条件(例如 can :read V2Report, user_id: @v2_post.user_id)。
您可以使用 load_and_authorize
资源,并在每次操作前让 CanCan 在您的控制器中设置实例变量。对于以更复杂的方式加载资源的操作,例如您的 V2Post.find(params[:id], include: :user_updates)
,您可以创建自定义 prepend_before_filter
方法来为特定操作加载资源。只要它是前置的,加载的实例就会被传递给 authorize_resource
方法。如果实例已经加载,load_and_authorize_resource
将不会对数据库进行额外的调用。
class V2PostsController < ApplicationController
prepend_before_filter :custom_load_resource, only: [:show, :edit]
load_and_authorize_resource
def show
render @v2_post
end
private
def custom_load_resource
@v2_post = V2Post.find(params[:id], include: :user_updates)
end
end
您也可以完全忘记 load_resource
,并在 100% 的时间使用您自己的 before_filter。或者,您可以放弃过滤器并从操作中调用 authorize!
。根据我最近的经验,上面详述的方法非常适用于 RESTful 控制器。
我在 Rails 3.2 应用程序中使用 CanCan 1.6.1。我在我的控制器中使用 authorize_resource
来限制用户可以 :read, :create, :update: and :delete
的内容。
在我的 V2Posts controller
中,authorize_resource
调用对我的 :show
操作无效。
在我的能力文件中,我试图限制用户只能阅读他们自己的帖子。没有错误,但不幸的是,他们可以查看其他用户的帖子。
class V2PostsController < ApplicationController
layout 'panel_layout', only: :show
before_filter :redirect_if_existing, only: [:new, :create]
authorize_resource
def show
@v2_post = V2Post.find(params[:id], include: :user_updates)
@organization = @v2_post.organization
respond_to do |format|
format.html
format.js
end
end
...
end
ability.rb:
class Ability
include CanCan::Ability
@user = nil
def initialize(user)
alias_action :taco,
:sandwich,
to: :read
@user = user
if user.is_in_role?(:admin)
can :manage, :all
else
default_rules
user.roles_list.each do |role|
meth = :"#{role}_rules"
send(meth) if respond_to? meth
end
end
end
def default_rules
cannot [:read, :create, :update, :destroy], :all
...
end
def pro_user_rules
can :read, V2Post, proid: @user.id
end
...
end
models/v2_post.rb:
class V2Post < ActiveRecord::Base
attr_accessible :proid, :user_updates_attributes, :organization
belongs_to :user, :foreign_key => "proid"
has_many :user_updates, as: :pro_post, dependent: :destroy
accepts_nested_attributes_for :user_updates
end
load_and_authorize_resource
用于阻止用户查看其他用户的帖子。但是,它会为我加载资源,还会为其他操作添加额外的数据库调用。 authorize_resource
不应该适用于我的情况吗?我已经在 show 动作中明确定义了 @v2_posts (我自己加载资源)。为什么它没有传递给 authorize_resource
调用?
- 我想避免额外调用数据库
- 我不想为自定义操作自动加载资源
- 我想授权每个 CRUD 操作。
鉴于此,load_and_authorize_resource
和 authorize_resource
哪个效果更好,每个 benefits/drawbacks 是多少?我已经阅读了文档,我很困惑。
问题是 authorize_resource
被 运行 用作前过滤器,并且直到在您的操作中 - 在调用 authorize_resource
之后才设置实例。当实例为nil时,authorize_resource
方法默认授权classV2Report
。授权 class 忽略属性条件(例如 can :read V2Report, user_id: @v2_post.user_id)。
您可以使用 load_and_authorize
资源,并在每次操作前让 CanCan 在您的控制器中设置实例变量。对于以更复杂的方式加载资源的操作,例如您的 V2Post.find(params[:id], include: :user_updates)
,您可以创建自定义 prepend_before_filter
方法来为特定操作加载资源。只要它是前置的,加载的实例就会被传递给 authorize_resource
方法。如果实例已经加载,load_and_authorize_resource
将不会对数据库进行额外的调用。
class V2PostsController < ApplicationController
prepend_before_filter :custom_load_resource, only: [:show, :edit]
load_and_authorize_resource
def show
render @v2_post
end
private
def custom_load_resource
@v2_post = V2Post.find(params[:id], include: :user_updates)
end
end
您也可以完全忘记 load_resource
,并在 100% 的时间使用您自己的 before_filter。或者,您可以放弃过滤器并从操作中调用 authorize!
。根据我最近的经验,上面详述的方法非常适用于 RESTful 控制器。