Setting CanCan ability.rs model
I successfully made login system with Devise and CanCan, and I have 3 types of users. Admin, internal and global users. I created Controllers and index actions: Admin, Cpanel, Report and State, and I want to restrict access to this controllers for some users.
Admin user should have privilegies to access: Reports(all), State (read), Admin (all)
Global user should have privilegies to access: Reports(only read), State(read), Cpanel(all)
Internal user should have privilegies to access: Reports(all), State (read)
And I tried to do this with following code in ability.rs:
class Abil开发者_运维知识库ity
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
if user.role? :admin
can :manage, [Report, Admin]
can :read, State
elsif user.role? :global_user
can :read, [Report, State]
can :manage, Cpanel
elsif user.role? :internal_user
can :manage, Report
can :read, State
end
end
end
At this time I have only index actions in this controllers, and when I login to app with internal user I CAN access to /admin for example, and that is not behavior that I want. I want to restrict access to all controllers instead of controllers listed in ability.rb class.
Source code is here
If I were going to prevent access to an entire controller, I would make a before filter that redirects the user to an access denied page if he does not have the admin role. Might look something like:
def check_permissions
raise CanCan::AccessDenied unless @current_user.role?(:admin)
end
If I just wanted to prevent access to update and create, for example, I would do:
def update
raise CanCan::AccessDenied unless can?(:update,Thing)
...
end
def create
raise CanCan::AccessDenied unless can?(:create,Thing)
...
end
You can handle the CanCan::AccessDenied
exception in your application controller:
rescue_from CanCan::AccessDenied do |exception|
flash[:error] = exception.message
redirect_to no_access_path
end
I have some pretty good posts about CanCan and Devise here and here
UPDATE I use this method in my application controller to set my current user variable:
# Make the current user object available to views
#----------------------------------------------------------------------------
def get_user
@current_user = session[:current_user]
end
You need to add checks for the cancan authorization to your controllers.
This might be just adding a line like
authorize! :read, @state
to your state controller index action, and similarly for all the other index actions.
EDIT: Sorry, in a state controller index action, you likely don't have @state, so the above wouldn't apply. Possibly something like
authorize! :read, State
There is also a load_and_authorize
method that you can use to combine authorization for multiple actions in a controller and reduce your code. The load_and_authorize
version is likely to look similar to
load_and_authorize_resource :state
and it should be before your actions.
You might want to look at this railscast on cancan authorization for a complete basic setup (in rails2).
I suspect to clear up other problems, we might need to see some more code. Try posting some of your controller code.
I haven't used this in rails3, but I assume most of it remains more or less similar.
I solved this problem with
def check_permissions
raise CanCan::AccessDenied unless current_user.role?(:admin)
end
but, note that I must to change @current_user
to current_user
(without @)
Thanks Tony
精彩评论