Ruby on Rails authorization gem to handle the following
Is there an authorization gem in Rails that handles something such as the following:
I have a user that wants to update their own profile. They'll invoke an HTTP POST to something such as http://example/users/:user_id/profile.xml
. The problem is, a lot of the code to handle tha开发者_JS百科t has something such as:
if params[:user_id] == current_user.id
# allow update!
else
# don't allow update
What authorization gem will allow for abstracting this out so that specifically, that logic can be automagically implied without me having to check it manually in every method that requires it?
Your question involves 2 parts:
- Authentication
- Authorization
Authentication in this case is basically the concept of allowing users to sign in and sign up to your website. You haven't mentioned this in your question, so maybe you've already implemented it. If you haven't, I'd advise you to look into Devise (here), its really easy to use but also really powerful.
Authorization is specifically what you asked about. That is, once a user is signed in, what privileges does that give him vs someone who's not. Also, what extra privileges do admins have and so on. Like others before me suggested, the best way to do this is to use CanCan (here).
I'm using both of these in the first rails app I've ever made, they are really easy to use.
Also, if you don't want such an extensive solution to authorization like CanCan, you could simply use a before_filter
and place your repeated code in there. I used this approach in another application, this post will help you out: (here)
First of all you don't want a gem, you are going to have to write your own code.
that logic can be automagically implied without me having to check it manually in every method that requires it?
That's what before_filters do. You will most likely already have one set up in your application_controller.rb. A before filter will ensure that the authorize method is called before every action that needs it See here unde section 7 Filters for more details on this http://guides.rubyonrails.org/action_controller_overview.html
Lastly, I hope you are not implying that xml post requests to update a profile should not log in! They surely should, http basic authentication will handle this for you.
See here http://api.rubyonrails.org/classes/ActiveResource/Base.html
Also for Rails => v 3.1 http://railscasts.com/episodes/270-authentication-in-rails-3-1
Update
It is clear from the comments below that it is not obvious how the suggestions I have provided help solve you problem
So here is how you could use the above information. A before filter in the application controller will ensure that the current user is ok so you don't need to check your controller params for a user id being == to the current users user id.
Secondly, if you want to know if a user is allowed to do a specific thing then add a method to the user class. something like
def can_do_something?
#Put your code here to check if something is allowed for this specific user
end
Then instead of
if params[:user_id] == current_user.id
# allow update!
else
# don't allow update
You add a validation to the model that you are trying to update (which is probably related to the user in some way) then you need no additional controller code at all above the authorization and authentication checks to deal with this or if that's not a good fit and you really have to put code in your controller then do this
if current_user.can_do_something?
# allow update!
else
# don't allow update
Authority
Your basic case would be handled by a simply finding the resource this way:
def update
# Best practice: only look for resources that belong to this user
@post = User.posts.find(params[:id])
...
end
If you need additional checks, my Authority gem makes it pretty easy. You define who can do what to resources by writing methods like updatable_by?
on Authorizer classes and letting your models delegate those questions to the authorizer. That way, models that have the same rules can just use the same authorizer.
In your controllers, you get some nice convenience methods:
class FoosController < ApplicationController
# Sets up some before_filter checks at the class level. In other words,
# if the user can never update any instance of Foo, they'll never even reach
# the update method
authorize_actions_for Foo
...
# Before this ever runs, we'll have asked if any Foo is ever `updatable_by?`
# the current user; if not, they'll see your "access denied" page.
def update
# If they got this far, they can at least update **some** Foo instances
# (though maybe not this one)
@foo = current_user.foos.find(params[:id]) # this alone handles ownership check
# Now that we know the specific instance, we can ask whether **this** Foo is
# `updatable_by?` the user. This shorthand method checks with the authorizer and
# shows the "access denied" page if the answer is false.
authorize_action_for(@foo)
...
end
end
Since you're just writing plain Ruby methods on the authorizers, you can check anything you know how to check in Ruby.
def updatable_by?(user)
resource.community_owned? && user.points > 20 || user.has_role?(:moderator)
end
See the detailed README for more info.
精彩评论