I tried this in the config:
### Popular gems integration
config.authenticate_with do
warden.authenticate! scope: :user
end
config.current_user_method(&:current_user)
here, accessing /admin
gets me stuck in a login loop. I login then get redirected to the login page.
Previously I had tried
class Ability
include CanCan::Ability
def initialize(user)
# Define abilities for the passed in user here. For example:
#
user ||= User.new # guest user (not logged in)
if user.admin?
with the CanCanCan authentication in rails admin config. This resulted in user always being nil. Even when I put in
config.current_user_method(&:current_user)
How do I fix this to authenticate was an admin?
EDIT: in sessions controller
if user.admin
redirect_to rails_admin_url
else
render json: user
end
and I get stuck in the redirect back to signin.
Routes:
Rails.application.routes.draw do
mount RailsAdmin::Engine => '/admin', as: 'rails_admin'
devise_for :users, controllers: { sessions: :sessions },
path_names: { sign_in: :login }
... then many resources lines
EDIT:
Sessions Controller:
class SessionsController < Devise::SessionsController
protect_from_forgery with: :null_session
def create
user = User.find_by_email(sign_in_params[:email])
puts sign_in_params
if user && user.valid_password?(sign_in_params[:password])
user.generate_auth_token
user.save
if user.admin
redirect_to rails_admin_url
else
render json: user
end
else
render json: { errors: { 'email or password' => ['is invalid'] } }, status: :unprocessable_entity
end
end
end
Rails admin config, trying this:
### Popular gems integration
config.authenticate_with do
redirect_to merchants_path unless current_user.admin?
end
config.current_user_method(&:current_user)
In ApplicationController:
def current_user
@current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
Tried this, current_user is nil.
THE CONTROLLER LOGIC FOR REDIRECT
The solution from Guillermo Siliceo Trueba will not work with your Users::SessionsController#create
action as you are not calling in the parent class create
action through the keyword super
.
The method create
from the class Devise::SessionsController
will run respond_with
in the last line using as location
the value returned from after_sign_in_path_for(resource)
class Devise::SessionsController < DeviseController
# POST /resource/sign_in
def create
self.resource = warden.authenticate!(auth_options)
set_flash_message!(:notice, :signed_in)
sign_in(resource_name, resource)
yield resource if block_given?
respond_with resource, location: after_sign_in_path_for(resource)
end
end
I am using this solution in my Users::SessionsController
to handle html
and json
requests and you can implement the same.
If the controller receives the request
with format .json
, the code between format.json do .. end
is executed, if the request
arrives with format.html
the parent method is called (I cover all your scenarios).
Rails router identifies the request format from the .json
or .html
appended at the end of the url (for example GET https://localhost:3000/users.json
)
class Users::SessionsController < Devise::SessionsController
def create
respond_to do |format|
format.json do
self.resource = warden.authenticate!(scope: resource_name, recall: "#{controller_path}#new")
render status: 200, json: resource
end
format.html do
super
end
end
end
end
The html
request will be routed to the super
create action. You just need to override the method def after_sign_in_path_for(resource)
from the parent as I am doing in my ApplicationController
.
if resource.admin
then just return rails_admin_url
from this method and skip the other lines, otherwise follow the normal behavior and call super#after_sign_in_path_for(resource)
def after_sign_in_path_for(resource)
return rails_admin_url if resource.admin
super
end
THE ERROR MESSAGES FOR AUTHENTICATION
warned.authenticate!
will save inside self.resource.errors
the error messages. You just need to display the errors on your device using json_response[:error]
and manipulating the response in your frontend.
I am rendering them in the SignInScreen
Component
THE TOKEN AUTHENTICATION
user.generate_auth_token
user.save
I use the simple_token_authentication
for devise which also allows you to regenerate the token every time the user signs in.
You just install the gem and add acts_as_token_authenticatable
inside your user
model.
class User < ApplicationRecord
acts_as_token_authenticable
end
You pass headers X-User-Email
and X-User-Token
with the corresponding values as explained in their guide.