In my application, I need to sign out specific users from time to time. And I need to do it from the interface or from a sidekiq worker. So I would like to create a sign_out method in my user model.
I saw in the documentation that devise provides a sign_out method but only in the controller. Is there a way to access to this method from a model or something similar.
Thanks
You need to read this answer https://stackoverflow.com/a/24388643/4269732 first.
If I was to implement this behavior then I would have added a column in User Model like expire_at_next_request?
Then just check this value in before_filter and logout the user if this is true.
class ApplicationController < ActionController::Base
before_filter :logout_if_requested
def logout_if_requested
if current_user && current_user.expire_at_next_request?
current_user.update_attributes(:expire_at_next_request=>false)
sign_out current_user
redirect_to :new_session_path
end
end
Related
I am using Devise gem for Authentication and ActiveAdmin gem which also uses Devise gem as dependency. I want to enable 2FA for ActiveAdmin, that's why I want to over ride after_sign_in_path_for method. I am able to over ride the method in ApplicationController but doesn't sounds right to me because this will affect our normal login as well. Is there any way to over ride after_sign_in_path_for only for ActiveAdmin. Currently this is how I am doing
class ApplicationController < ActionController::Base
def after_sign_in_path_for
end
end
If I can't only over ride only ActiveAdmin controller then how to deal with normal login without 2FA and ActiveAdmin login with 2FA. Something like this.
class ApplicationController < ActionController::Base
def after_sign_in_path_for(resource)
if resource.instance_of?(AdminUser)
redirect_to setup_2fa_path
else
super # <-------- is this possible or is this correct ?
end
end
end
There must be a way where I can only over ride after_sign_in_path_for for ActiveAdmin. Or do I need to over ride ActiveAdmin::Devise::SessionsController class in initializer? Putting controller login inside initializer also don't feel right to me.
UPDATE
I noticed there is one more problem, when control reaches after_sign_in_path then current_admin_user is already set. This is problem because user can skip setting up 2FA and type path in browser like localhost:3000/admin and they are in because there is current_admin_user. I can set current_admin_user to nil in after_sign_in_path but I am not sure if that will open door to other type of attacks ? How should I deal with this ? or shall I try to over ride different method ? I don't know if there is something like before_sign_in_path_for or something else.
An approach is to open up and extend the Devise::SessionsController within ActiveAdmin. I managed to implement 2fa with a one time password based on code discussed at https://medium.com/#acesubido/adding-two-factor-authentication-in-activeadmin-2ed134b60042 and https://medium.com/#acesubido/part-2-adding-two-factor-authentication-in-activeadmin-cc5eab67057c
Also: https://blog.kiprosh.com/adding-two-factor-authentication-2fa-for-activeadmin-auth-in-a-ruby-on-rails-web-application/ can be of inspiration, I chose for the first setup with a 2 step process. Also you may want to consider a before_action in you ApplicationController that allows for users to setup their 2fa after logging in:
def check_2fa
return if current_admin_user.nil?
redirect_to user_dashboard_two_factor_new_path \
if current_admin_user.force_2fa && !current_admin_user.otp_required_for_login
end
Good luck.
I need to logout a user that has been logged in my Rails app using custom Devise authentication strategy. This strategy is used in addition to database_authenticable strategy. Is there a logic I need to add to my custom implementation of authenticate_user! method in custom strategy? Also do I need to implement destroy method in a custom sessions controller?
Currently my custom strategy logs in the user fine (hard coded for now) but I cannot logout the user as logout action calls my custom implementation of authenticate_user! again and they are logged in again.
You can use skip_before_action callback in this case like in your controller put below code before all actions
skip_before_action :authenticate_user, only: [:your_logout_action]
This will skip authentication for your method and user won't log in again.
So far as I understood correctly, is that, let any action to logout the current_user in devise. If it's so then it can be implemented like this
Let's say ,
class SomeController < ApplicationController
before_action :authenticate_user!
def some_action
if some_logic == true #implement some_logic to return boolean(true/false)
sign_out resource
flash[:notice] = ''
flash[:error] = 'You are logged out!'
root_path
end
end
end
I was able to fix my issue. The issue was that I had hard coded valid? method to return true all the time. When I added the logic to return true only if email and password params are present then the custom auth works as expected.
Make user log out by manually.
sign_out(current_user) if current_user.present?
EDIT: I use Devise 3.4.1, and after_remembered isn't available. Either apply this small patch or use a newer version released after 2014/11/09.
Alright, so I am rather new to the Rails environment, and I feel I am missing something.
I wish to execute a particular action after login, be it after login from a form or automatic login.
I found out that after_sign_in_path_for is executed after a "regular" login. I already use it in my Application controller.
class ApplicationController < ActionController::Base
[…]
def after_sign_in_path_for(resource)
myAction
end
However, it seems that this method isn't called when a user is logged in through the Devise Remember option.
I found out that after_remembered is executed after a user is automatically logged in, however I don't understand how to use it. I don't want to modify the Devise gem just to add my action to the method, and the following doesn't seem to work:
class ApplicationController < ActionController::Base
[…]
def after_remembered()
myAction
end
I am at a loss here. Either I don't understand how to use after_remembered, or I look at it the wrong way and there is another solution for that (should it cover either both cases or only the case with "remember me" automatic login, is fine for me). Does anyone have any idea to make it work?
PS: I am working on an app I haven't developed myself. If you feel you need more code in order to answer, tell me and I will edit my post.
It's part of the Rememberable module so it belongs in your model... assuming your resource is User the way you would use it is...
class User < ActiveRecord::Base
devise :rememberable
def after_remembered
# (your code here)
end
end
I'm not sure if Devise offers a controller-specific method but if not you could throw one togeter... create an attribute in your User model called, say, signed_in_via_remembered
class User < ActiveRecord::Base
devise :rememberable
def after_remembered
update_attribute(:signed_in_via_remember, true)
end
end
then in your application_controller.rb
class ApplicationController < ActionController::Base
before_action :handle_sign_in_via_rememberable
def handle_sign_in_via_rememberable
if current_user and current_user.signed_in_via_remember?
current_user.update_attribute(:signed_in_via_remember, false)
after_sign_in_path_for(User)
end
end
def after_sign_in_path_for(resource)
myAction
end
end
Someone may have a neater solution.
My user model has the attributes password, password_confirmation, username, email, and admin.
I'm wondering how exactly do I check whether the currently logged in user is an admin. How would I go about the methods? I've tried if user.admin? on my views, but it seems that doesn't work.
I'm new to rails so any suggestions would be helpful!
There is a "session" hash which persists through the whole session.
Once a user has logged in, you would store the current user's id in the session hash, like so
session[:user_id] = user.id
Now, if you want the current user to be accessible from your controllers and in your views, you can go to apps/controllers/application_controller and make some useful methods...
class ApplicationController < ActionController::Base
protect_from_forgery
helper_method :current_user, :signed_in?, :is_admin?
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
def signed_in?
!!current_user
end
def is_admin?
signed_in? ? current_user.admin : false
end
end
Now in your views you can use "is_admin?" to check if the current user is an admin, use
"signed_in?" to check if a user is signed in, and "current_user" to access the user object if it exists (if no user is logged in, "current_user" will be nil)
Cheers
I suggest you to consult with this Devise guide. It shows how to create a basic user model with help of Devise and how to perform admin checks. And yes, by giving you this link, I strongly encourage you to use Devise gem for users and all that stuff ;)
I have a customer devise controller and i wan to set my sign up action to update a user status to online when the user signs in and off line when the users logout. I have
def signin
super
end
I want to update the users status attribute to online on login and offline on logout. Pls any help here
You may be missing attr_accesible declaration for the "status" attribute of User table?
You can use the after_sign_in_path_for and after_sign_out_path_for hooks provided in devise. Just override those methods in your ApplicationController. Eg.
class ApplicationController < ActionController::Base
private
def after_sign_in_path_for(resource_or_scope)
#update user status to online
root_path
end
def after_sign_out_path_for(resource_or_scope)
#update user status to offline
root_path
end
end
More info here: devise wiki