示例:
用户A(id=10)创建了照片资源
photo: (id: 1 user_id = 10, url: "http://...")
现在,如果用户B(id=20)转到这个url:/photos/1/edit
,它可以编辑用户A的照片!!!
Rails+Devise默认情况下为此提供了什么?似乎是一个很常见的问题
我只需要允许任何用户都可以编辑/删除它创建的ONLY资源(其中current_user==resource.user)
使用:Rails 4,Devise
更新:
我觉得CanCan太高级了。我不需要角色,也不需要将某些操作限制为特定用户
在您的PhotosController:中
before_filter :require_permission, only: :edit
def require_permission
if current_user != Photo.find(params[:id]).user
redirect_to root_path
#Or do something else here
end
end
您可以利用Rails的关联并像这样编写:
def edit
@photo = current_user.photos.find(params[:id])
# ... do everything else
end
只有当提供ID的照片属于当前用户时,才会找到记录。如果没有,Rails将引发一个ActiveRecord::RecordNotFound
异常。
当然,我假设current_user
方法是可用的,并且您的User
模型包含语句has_many :photos
。
检查此轨道支架,
http://railscasts.com/episodes/192-authorization-with-cancan
,您将遇到的并发症
-
当你想取消Devise gem用于身份验证的用户模型的授权时
-
当您想将您的角色存储在数据库中时
-
当您想从webUI 以管理员身份为角色分配权限时
-
等等。。
如果你想要这些功能中的任何一个,请发表评论,我很乐意提供帮助,因为我最近在其他人的大力帮助下完成了这些功能,并且它总是令人惊叹的。
您的资源的示例能力可以如下所示,
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest users
send(user.role.name)
if user.role.blank?
can :read, User #for guest without roles
end
end
def man
can :manage, Photo
end
def boy
can :read, Photo
end
def kid
can :read, Article
end
end
我从before_filter操作中捕获了异常:
before_action :set_photo, only: [:edit, :update, :destroy]
def set_photo
@photo = current_user.photos.find(params[:id])
rescue ActiveRecord::RecordNotFound
redirect_to(root_url, :notice => 'Record not found')
end
希望这能帮助到别人。我使用的是Rails 4和Ruby 2。
所以您使用的是gem devise
。
此gem为当前登录的用户提供current_user
。
在您的PhotosController#edit
方法中。我会做下面这样的事情。
def edit
@photo = Photo.find(params[:id])
redirect_to root_path, notice: 'Thou Shalt Nought duuu dat :(' unless current_user.id == @photo.user_id
...
end
这种方法比较便宜,因为您已经有两个对象要比较,而不是在比较中运行查询。
最简单的方法是修改routes.rb.
将照片分配到current_user路径中。
例如,
devise_for :users
resources 'users' do
resources 'photos'
end
cancan既困难又复杂我有编码is_onwer
的方法它非常简单,容易
https://gist.github.com/x1wins/0d3f0058270cef37b2d3f25a56a3745d
应用控制器
def is_owner user_id
unless user_id == current_user.id
render json: nil, status: :forbidden
return
end
end
def is_owner_object data
if data.nil? or data.user_id.nil?
return render status: :not_found
else
is_owner data.user_id
end
end
您的控制器
before_action only: [:edit, :update, :destroy] do
is_owner_object @article ##your object
end
如果CanCan太高级,您应该使用…检查控制器中访问器的id。。。
if @user.id == @photo.user_id
# edit photo details
else
redirect_to root_path, notice: "You! Shall! Not! Edit!"
或者类似的东西
在application_controller:中编写另一个before_filter
before_filter :has_permission?
has_permission?
controllers=["articles", "photos", "..."]
actions=["edit", "destroy", "..."]
id = params[:id] if (controllers.include?(params[:controller] && actions.include?(params[:action]) end
if id && (current_user.id==(params[:controller][0...1].capitalize!+params[:controller].singularize[1...-1] + ".find(#{id}).user_id").send)
return true
else
redirect_to root_url, :notice=>"no permission for this action"
end
helper_method :has_permission?
你可以在视图中使用它,而不是向用户显示他们无法关注的链接。
某种类型的,当然你需要修改它以满足你的需求。