15

例子:

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

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

现在,如果用户B (id=20) 转到这个 url:/photos/1/edit它可以编辑用户A 的照片!!!

Rails+Devise默认为此提供了一些东西?这似乎是一个非常普遍的问题

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

使用: Rails 4,设计

更新:

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

4

9 回答 9

37

在您的照片控制器中:

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
于 2013-07-22T17:36:39.030 回答
17

你可以利用 Rails 的关联,这样写:

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

  # ... do everything else
end

只有当提供的 ID 的照片属于当前用户时,才会找到一条记录。如果没有,Rails 将引发ActiveRecord::RecordNotFound异常。

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

于 2013-07-22T20:05:57.467 回答
3

检查这个railscasts,

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

你会遇到的并发症,

  1. 当您想要对 Devise gem 用于身份验证的用户模型进行 cancan 授权时

  2. 当您想将角色存储在数据库中时

  3. 当您想从 WebUI 以管理员身份将权限分配给角色时

  4. 和更多 ..

如果您想要这些功能中的任何一个,请发表评论,我很乐意提供帮助,因为我最近在其他人的大力帮助下完成了这些功能,并且传递它总是令人惊奇。

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

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
于 2013-07-11T14:06:14.743 回答
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。

于 2014-01-09T19:41:57.757 回答
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 个对象要比较,而不是在比较中运行查询。

于 2013-07-26T11:44:27.967 回答
1

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

将照片分配到 current_user 路径中。

例如,

devise_for :users

resources 'users' do 
  resources 'photos'
end
于 2013-07-29T16:30:33.287 回答
1

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
于 2019-07-30T20:19:06.520 回答
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?

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

当然,您需要对其进行修改以满足您的需要。

于 2013-07-11T13:56:45.713 回答
0

如果 CanCan 太高级,您应该使用...检查控制器中访问器的 ID。

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

...或类似的东西

于 2013-07-22T17:51:34.567 回答