I have been using devise and cancancan for authentication and authorisation resp., resque for background jobs. I have been following Ryans screencast number 271 and saw below code snippet for routes.rb file.
authenticate :admin do
mount Resque::Server, :at => "/resque"
end
to authenticated user, but in my case I have only users table and admin is also users separated by role column, Now I would like to authenticate and authorise the route for resque server path based on users role, How can I achieve solution for this problem ?
authenticate :user do
mount Resque::Server, :at => "/resque"
end
works fine for logged in user but i want it to be accessible only to admin user. Any help will be heartly appreciated.
# config/initializers/admin.rb
class CanAccessResque
def self.matches?(request)
current_user = request.env['warden'].user
return false if current_user.blank?
Ability.new(current_user).can? :manage, Resque
end
end
# routes.rb
namespace :admin do
constraints CanAccessResque do
mount Resque::Server, at: 'resque'
end
end
# ability.rb
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
if user.is_admin?
can :manage, Resque
end
end
end
# user.rb
class User < ActiveRecord::Base
def is_admin?
# your admin logic here for example:
self.role == "admin"
end
end
OR for more information, check this blog out: resque-admin-in-rails-routes-with-cancan
Hope this helps you.
Related
I have a Rails 3.2.x app using the rails_admin gem on the back end. I'm also using Devise for authentication and have a role field on the User model to say whether or not the user is an admin or employee.
What I'm trying to do is setup an authorization for rails_admin so if you visit http://domain.com/admin it will only allow it if the current_user.role == "admin" otherwise redirect to my home controller index path home_index_path
I've setup an initializer that should do this, and it does deny admin access if the role is not admin, but I get the following error: No route matches {:controller=>"home"}. I'm thinking it might have to do with the routes.rb and where I have the RailsAdmin line mounted in routes.rb but am not sure. Ultimately this should check the role to make sure it's equal to admin if not, redirect_to home_index_path and flash a message.
Any help is greatly appreciated.
rails_admin.rb
RailsAdmin.config do |config|
config.authorize_with do |controller|
unless current_user.role == 'admin'
flash[:error] = "You are not an admin"
redirect_to home_index_path
end
end
end
After some google searching I found an issue that addresses this. It looks like the namespace is different so redirecting to `main_app.root_path did the trick. I still cannot get the flash message to work. Any thoughts on this?
RailsAdmin.config do |config|
config.authorize_with do |controller|
unless current_user.role == 'admin'
redirect_to main_app.root_path
flash[:error] = "You are not an admin"
end
end
end
My CanCan implementation is denying access when I have called the can method with :create specified. Here is my ability implementation:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # User is not logged in (Guest)
if user.id == nil # Guest user
can [:create, :update], Device
else
if user.admin?
can :manage, :all
else
can :manage, Spot, :user_id => user.id
end
end
end
end
Basically I want non-authenticated users to be able to submit POST and PUT requests to the create and update actions of my Devices controller. However, when I try to submit a POST request the request is denied by CanCan (I'm asked to log in).
At the top of my devices controller I simply call load_and_authorize_resouce.
Does anyone see why CanCan would be raising an AccessDenied exception on this?
Can Active Admin use my current Devise user model? It already has a column named admin, and if it's true, I'd like to bypass the Active admin login, when going to /admin.
Is this possible?
Current routes:
#Active admin
ActiveAdmin.routes(self)
#Devise
devise_for :admin_users, ActiveAdmin::Devise.config
devise_for :users, :path => "account"
The rest is basically standard Devise + Active admin
Yes you can do that, when running the generator skip the user model creation:
rails generate active_admin:install --skip-users
Then in your config/initializers/active_admin.rb :
# == User Authentication
#
# Active Admin will automatically call an authentication
# method in a before filter of all controller actions to
# ensure that there is a currently logged in admin user.
#
# This setting changes the method which Active Admin calls
# within the controller.
config.authentication_method = :authenticate_admin!
uncomment config.authentication_method and provide your authentication method for your admin, for example:
# app/controllers/application_controller.rb
def authenticate_admin!
redirect_to new_user_session_path unless current_user.is_admin?
end
Restart your server and It should be working. Also Take a look to Active Admin Configuration
Hope this helps.
As stated earlier, you will need to update your config/initializers/active_admin.rb to reflect the correct auth method.
Additionally, however, you will want to update the following settings as well:
# This setting changes the method which Active Admin calls
# to return the currently logged in user.
config.current_user_method = :current_admin_user
to
config.current_user_method = :current_user
and
# This setting changes the path where the link points to. If it's
# a string, the strings is used as the path. If it's a Symbol, we
# will call the method to return the path.
#
# Default:
config.logout_link_path = :destroy_admin_user_session_path
to
config.logout_link_path = :destroy_user_session_path
Of course, you don't HAVE to update these (or the method mentioned in the post), and just over-ride the methods elsewhere, but this seems to be the easiest / cleanest approach. You will obviously need to substitute "user" in each setting (current_USER) with the name of the model using devise authentication.
I would also recommend updating the following setting as well while you are in there:
# This setting changes the http method used when rendering the
# link. For example :get, :delete, :put, etc..
#
# Default:
config.logout_link_method = :get
to
config.logout_link_method = :delete
This last change is required if the default HTTP method used by your devise config is set to :delete, which it is unless you changed it. It matters that they are now synced because if you follow these instructions, you will be using destroy_user_session_path which is a path already defined by devise. Otherwise you will get a message stating that [GET] /users/sign_out route does not exist.
Here's the process if you have already installed ActiveAdmin with default settings, and you want to authenticate users with User.is_admin field on your existing model, and remove admin_user table:
Rollback admin_user migrations (if you didn't use --skip-users when installing Active Admin):
rake db:migrate:down VERSION=20141205110842 # create_active_admin_comments.rb
rake db:migrate:down VERSION=20141205110831 # add_devise_to_admin_users.rb
rake db:migrate:down VERSION=20141205110820 # devise_create_admin_users.rb
Then remove those 3 files.
In routing, remove the line devise_for :admin_users, ActiveAdmin::Devise.config
In application_controller.rb, add:
def authenticate_admin!
if current_user && current_user.is_admin
# fine
else
redirect_to new_user_session_path
end
end
In active_admin.rb:
config.authentication_method = :authenticate_admin!
config.current_user_method = :current_user
config.logout_link_path = :destroy_user_session_path
config.allow_comments = false
config.logout_link_method = :get # couldn't get active_admin to sign out via :delete. So I configure devise to sign out via :get.
To configure devise to sign out via :get, add in devise.rb:
config.sign_out_via = :get
# And for every occurrence of destroy_user_session_path, remove the option method: delete.
Create is_admin migration:
rails g migration add_is_admin_to_user is_admin:boolean
Edit the migration like so:
class AddIsAdminToUser < ActiveRecord::Migration
def change
add_column :users, :is_admin, :boolean, default: false
end
end
And migrate:
rake db:migrate
If in rails 4, don't forget to add is_admin in permit_params. In app/admin/user.rb:
permit_params ....., :is_admin
Add rights to admin users, in a console:
u = User.find(42); u.is_admin = true; u.save
Enjoy
All of what everyone else has said as well as in conjunction with the guide laid out at
http://dan.doezema.com/2012/02/how-to-implement-a-single-user-model-with-rails-activeadmin-and-devise/
that adds some additional bits on information if you are choosing to revert back to the option to have a single user model when you have already implemented an admin_user model (ie right now you have a 'user' as well as an 'admin_user' model).
The additional steps included
remove devise_for :admin_users, ActiveAdmin::Devise.config from routes.rb
copy code from app/admin/admin_user.rb to app/admin/user.rb (only use what is required)
delete app/admin/admin_user.rb (or you will get an Uninitialized constant error on AdminUser) like this guy had (and me as well).
I'm using active admin in my rails 3.0.9 app with the default setup.i.e I have User model with devise authentication for customer login and Active Admin is running on AdminUser model. All Ok apart from the active admin login page. When I try to access http://localhost:3000/admin I get the active admin login page very quickly. But after I enter the username/password correctly/incorrectly the authentication process takes nearly 3-5 minutes. Because of this reason I can't even deploy the app on heroku, and I get timeout errors on heroku logs.
But how ever in development mode after I logged in to active admin, everything works perfectly. I'm assuming this is happening due an issue with routing. So I'm pasting my routes file here with fully.
http://pastie.org/3153643
Can some one help me on this please? Thanks
UPDATE 09-Jan: Its seems like the issue is not related to the routes I think. I removed all the other models/controllers/views/routes leaving only User and AdminUser stuffs. But I still experiencing the slowness.
Never mind I've found the issue and the probably the solution as well. I'm posting it here so it will help someone else with a similar issue.
In my application I was originally using authlogic gem for authentication but recently I've switched over this to devise for better support. But I still wanted to allow old users to login to the app with same passwords. So I've overridden the devise encryption from Bcrypt to Authlogic's sha512 as below.
config/initializers/devise.rb
config.encryptor = :authlogic_sha512
But I never change the AdminUser model to fit with the above change.
So the fix should be in my model I should use the :encryptable and :encryptor => :authlogic_sha512
class AdminUser < ActiveRecord::Base
devise :database_authenticatable,
:recoverable, :rememberable, :trackable, :validatable,:encryptable, `:encryptor => :authlogic_sha512`
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me
end
And in AdminUser migration file encryptable columns should be enabled
create_table(:admin_users) do |t|
t.database_authenticatable :null => false
t.recoverable
t.rememberable
t.trackable
t.encryptable
# t.confirmable
# t.lockable :lock_strategy => :failed_attempts, :unlock_strategy => :both
# t.token_authenticatable
t.timestamps
end
I'm using Devise and OmniAuth (Facebook) in a Rails 3 app. I just started noticing this behavior recently.
When a user signs in, he is redirected to his dashboard, however, the characters "#_" are being appended to the url. The only thing I can think of now is a conflict between the routes created by:
resources :users
and
# User Authentication
devise_for :users,
:singular => :user,
:controllers => {:registrations => 'registrations'} do
get 'logout' => 'devise/sessions#destroy'
end
Is this only happening with Facebook? If so it is probably related to: https://developers.facebook.com/blog/post/552/. Notice how Facebook outlines that they changed the session redirect handling to append a #_=_ to responses. I'm not sure why this was done, however you may be able to fix it by supplying an explicit redirect url.