Rails role-based auth with roles stored in database - ruby-on-rails

Does exists gem, that implements following things:
User can has many roles
Each role has group of permissions
Each permission just boolean
Roles and permissions stored in database (most important)
For example, I want for something like this:
if current_user.can?(:read_all, :list_of_orders)
...
end
And can? method should search, does any of roles allows it.

Following Zippie question, I suggest you going with CanCan but you can also use along with it for authentication. See the following links which you will find useful Rails 3 Authentication and Authorization with Devise and CanCan (Part 1) & Rails 3 Authentication and Authorization with Devise and CanCan (Part 2).
You could potentially have something like this in your ability.rb
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user
# raise user.role?(:administrator).inspect
if user.role? :administrator
can :manage, :all
can :manage, User
elsif user.role? :employee
can :read, :all
end
end
end
So that in your views you can do something like
You can also use the can? in your controller to create your necessary filters as well.

See devise for user authentication and you can define your roles there:
https://github.com/plataformatec/devise
or even better, combine it easily with cancan:
https://github.com/ryanb/cancan/wiki/Role-Based-Authorization

You can try cancan gem, It is powerful
https://github.com/ryanb/cancan
for example:
<% if can? :update, #article %>
<%= link_to "Edit", edit_article_path(#article) %>
<% end %>
you can Defining Abilities in a ability.rb
can :manage, Article # user can perform any action on the article
can :read, :all # user can read any object
can :manage, :all # user can perform any action on any object

Related

Why does the output is not passing through the ability check in Role Based Authorization (One Role Per User)

I want 3 user levels as Admin ,Manager,Customer in my rails application. So i've created a devise model as Users and added a migration to add the user role to it.So when a user is signed up it stores the users role(whether he is an admin,a manager or a customer). And in my application there are models and controllers for product,delivery,services. And I want to set access levels to each models.
So Admin have access to all models, controllers
Manager have access to Product, Delivery
Customer have access to Services
And i've written the Ability model as follows.
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
if user.roles == "admin"
can :manage , :all
elsif user.roles == "manager"
can :read, Products, Delivery
elsif user.roles == "customer"
can :read, Services
end
end
end
My show view for the product is as follows.
<% if can? :manage ,#products%>
<h1>Products</h1>
<% #products.each do |product| %>
<p> <%= product.name%>
<p> <%= product.price %><br>
<p> <%= product.qty %><br>
<%end%>
<%end%>
But even i sign in as an admin the data is not displayed.
I'm referring the following cancan documentation.
https://github.com/CanCanCommunity/cancancan/wiki/Role-Based-Authorization
The code seems to be okay with "One role per user"
But the data is not displayed.Please help me to solve this issue.
I'm no real expert at CanCan, but You may try:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
cannot :manage, :all # we can do this since the abilities are OR'ed
if user.roles.include?('admin')
can :manage , :all
elsif user.roles.include?('manager')
can :read, Products, Delivery
elsif user.roles.include?('customer')
can :read, Services
end
end
end
Besides, if it's a project start, think about CanCanCan
https://github.com/CanCanCommunity/cancancan
It's updated version of CanCan, still maintained by the Community.
All the codes were correct but the issue was with the strong parameters.Therefor when signing up "role" has not saved in the database.Therefor when the ability is checked the users are not passed to view the content as non of they are admins,managers or customers

Why can user create posts if `cannot :manage, Post` in Ability class (CanCanCan)?

I'm implementing CanCanCan for the first time.
But am confused why users can still create posts when I've setup cannot :manage, Post in the Ability class.
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # if a non-signedin visitor
cannot :manage, Post
end
end
My understanding is that :manage applies to all actions, so the user should not be able to do anything with the post resource.
Can anyone advise?
have you added this around the index, show and edit pages CRUD links across your app? that will remove the link all together.. Im still new with cancancan but even with the load_and_authorize_resources I still had to add the if can? around my links and that resolved my problem.
<% if can? :manage, Post %>
<% link_to "something" some_path %>
<% end %>
hope this helps
First, you need to define the abilities of each user type inside the Ability class:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # if a non-signedin visitor
# abilities of user of type PUBLISHER
if user.role == "publisher"
can :create, Post
can :read, Post
can :update, Post, user_id: user.id # users can only update their own posts
# abilities of user of type ADMIN
elsif user.role == "admin"
can :manage, :all # admin can do everything
# abilities of non-users (e.g. they only can read posts)
else
cannot :manage, Post
can :read, Post
end
end
Defining the abilities does not mean they are automatically
applicable in controllers.
Second, you need to include load_and_authorize_resource in each controller you want to apply the defined abilities to (e.g. the Post controller).

Understanding CanCan Ability and Users

I have Rails Admin with CanCan support in my rails app. I'm confused on one issue though. How does CanCan know what user is signed in? For example, my users can have different roles and through CanCan I assign roles for certain access into each table. When I go to localhost:3000/admin, I receive the error
CanCan::AccessDenied in RailsAdmin::MainController#dashboard
My Ability.rb file
def initialize(user)
if user and user.role.eql? :super_admin
can :manage, :all # allow superadmins to do anything
elsif user and user.role.eql? :admin
can :manage, [Location, School] # allow admins to manage only Locations and Schools
end
end
So what do I do so that user's have the ability to sign in into Rails Admin? Do I have to manually create it?
By default, CanCan will use whatever is returned by current_user. If you are using Devise within a namespace though (admin for example) then Devise actually will use current_admin_user instead. You can either create a current_user method in your ApplicationController (or some other base controller) that returns current_admin_user or overwrite the current_ability method to instantiate the Ability with current_admin_user instead.
(this is all assuming your Devise is using a namespace. By default Devise will use current_user)
You need to have a current_user method available in your controller. Assuming you have that, if you aren't signed you won't have access to a current user, so you'll need to assign a user in your ability file if it doesn't exist. In your initialize method, add user ||= User.new to make the assignment if a user doesn't already exist.
def initialize(user)
user ||= User.new
if user and user.role.eql? :super_admin
can :manage, :all # allow superadmins to do anything
elsif user and user.role.eql? :admin
can :manage, [Location, School] # allow admins to manage only Locations and Schools
end
end

Security: using CanCan to make sure user cannot see other users' profiles

I've got an app that uses Devise, CanCan and Rolify to deal with authentication and authorization. But I don't think I'm using these gems to the full extent. Right now the only thing in my ability class is this:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
if user.has_role? :admin
can :manage, :all
else
can :read, :all
end
end
end
I found a security hole where an authenticated user is able to look at other user profiles. I fixed it by changing some code in the user controller.
def show
#user = current_user.has_role?(:admin) ? User.find(params[:id]) : current_user
end
Is this the best way to deal with this hole? Is there a best practice or a rails convention that addresses this in a different way?
From the doc:
can :read, ModelName, :user_id => user.id

cancan gem simple question

models/ability.rb
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user
if user.role? :admin
can :manage, :all
else
can :read, :all
can :create, Comment
can :update, Comment do |comment|
comment.try(:user) == user || user.role?(:moderator)
end
if user.role?(:author)
can :create, Article
can :update, Article do |article|
article.try(:user) == user
end
end
end
end
end
In Railscasts there are methods user.role? :admin & if user.role?(:author).I dont get it. Do i need to create a method in model to make it work?
I'm storing roles in Users table as a role column.
Yes, you need to write this yourself. However, the CanCan project has a wiki page describing how to do this.
The first line of the wiki says:
"CanCan is decoupled from how you
implement roles in the User model, but
how might one set up basic role-based
authorization?"
Note that I disagree almost completely with the example on that page that uses a role_mask, but the page is still good and should give you some ideas.
There is also the Separate Role Model example, which I personally like better. It depends on where you want to store your role information.
If you're looking for a gem that is plug-and-play, then check out Declarative Authorization.
Raynb says that he developed Cancan because DA was overkill for some projects here: http://railscasts.com/episodes/192-authorization-with-cancan?autoplay=true

Resources