问题
Example:
User A (id=10) has created a photo resource
photo: (id: 1 user_id = 10, url: "http://...")
Now, if User B (id=20) go to this url: /photos/1/edit it can edit photo of user A!!!
Rails+Devise provides something for this by default? It seems it's a very common issue
I just need to allow that any user can edit/delete ONLY resource it has created (where current_user == resource.user)
Using: Rails 4, Devise
Update:
I think CanCan it's something too advanced. I don't need roles or restrict some actions to certain users
回答1:
In your 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
回答2:
You can make use of Rails' associations and write it like this:
def edit
@photo = current_user.photos.find(params[:id])
# ... do everything else
end
This will only find a record when the photo with the supplied ID belongs to the current user. If it doesn't, Rails will raise a ActiveRecord::RecordNotFound exception.
Of course, I'm assuming the current_user method is available and your User model contains the statement has_many :photos.
回答3:
Check this railscasts,
http://railscasts.com/episodes/192-authorization-with-cancan
Complications you will run into,
When you want cancan authorization on User Model that Devise gem is using for authentication
When you want to store your Roles in the Database
When you want to assign Permissions to the Roles as an Admin from the webUI
and more ..
Please comment if you want any of those features, I will be happy to help, because I recently did them with great help from others and its always amazing to pass it on.
A sample Ability for your resources can be like as follows,
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
回答4:
I captured the exception from within a before_filter action:
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
Hope this helps someone. I'm using Rails 4 and Ruby 2.
回答5:
So you are using gem devise.
This gem provides the current_user for the currently logged in user.
In your PhotosController#edit method. I'd do something like below.
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
This method is cheaper because you already have 2 objects to compare instead of running a query in the comparison.
回答6:
The simplest would be to to modify routes.rb.
Assign photos to live in the current_user path.
For example,
devise_for :users
resources 'users' do
resources 'photos'
end
回答7:
cancan is difficult and complicate
i have coding is_onwer method
it's very simple, easy
https://gist.github.com/x1wins/0d3f0058270cef37b2d3f25a56a3745d
application controller
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
your controller
before_action only: [:edit, :update, :destroy] do
is_owner_object @article ##your object
end
回答8:
If CanCan is too advanced, you should loon into checking the id of the accessor in the controller using...
if @user.id == @photo.user_id
# edit photo details
else
redirect_to root_path, notice: "You! Shall! Not! Edit!"
...or something like that
回答9:
Write another before_filter in application_controller:
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?
And you can use it in views, not to show users link they can't follow.
Some kind of this, of course you need to modify it to suit your needs.
来源:https://stackoverflow.com/questions/17594939/check-if-current-user-is-the-owner-of-a-resource-and-allow-edit-delete-actions