检查current_user是否是资源的所有者并允许编辑/删除操作

时间:2013-07-11 13:39:00

标签: ruby-on-rails activerecord devise ruby-on-rails-4

示例:

用户 A (id = 10)创建了照片资源

photo: (id: 1 user_id = 10, url: "http://...")

现在,如果用户 B (id = 20)转到此网址:/photos/1/edit,则可以编辑用户的照片 A !!!

Rails + Devise 默认提供此功能?这似乎是一个非常普遍的问题

我只需要允许任何用户只能编辑/删除它创建的资源(其中current_user == resource.user)

使用: Rails 4,设计

更新:

我认为CanCan太先进了。我不需要角色或限制某些用户的某些操作

9 个答案:

答案 0 :(得分:33)

在你的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

答案 1 :(得分:14)

您可以使用Rails的关联并按如下方式编写:

def edit
  @photo = current_user.photos.find(params[:id])

  # ... do everything else
end

仅当具有提供的ID的照片属于当前用户时,才会找到记录。如果没有,Rails将引发ActiveRecord::RecordNotFound例外。

当然,我假设current_user方法可用且您的User模型包含语句has_many :photos

答案 2 :(得分:3)

检查此railscast,

http://railscasts.com/episodes/192-authorization-with-cancan

您将遇到的并发症,

  1. 如果您想在Devise gem用于身份验证的用户模型上进行cancan授权

  2. 如果要将角色存储在数据库中

  3. 如果要从WebUI为管理员分配权限

  4. 以及更多..

  5. 如果您想要任何这些功能,请发表评论,我将很乐意为您提供帮助,因为我最近在其他人的帮助下完成了这些功能,而且总是令人惊叹地传递它们。

    示例资源的能力可以如下所示,

    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
    

答案 3 :(得分:2)

我从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。

答案 4 :(得分:1)

所以你正在使用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

此方法更便宜,因为您已经有2个对象需要比较,而不是在比较中运行查询。

答案 5 :(得分:1)

最简单的方法是修改routes.rb。

将照片分配到current_user路径中。

例如,

devise_for :users

resources 'users' do 
  resources 'photos'
end

答案 6 :(得分:1)

康康舞曲既困难又复杂 我有编码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

答案 7 :(得分:0)

在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?

您可以在视图中使用它,而不是向用户显示他们无法关注的链接。

某种,当然你需要修改它以满足你的需要。

答案 8 :(得分:0)

如果CanCan过于先进,您应该使用...来检查控制器中访问者的ID ...

if @user.id == @photo.user_id
  # edit photo details
else
  redirect_to root_path, notice: "You! Shall! Not! Edit!"

......或类似的东西