Does devise have call backs when a user signs in and out?
This is what I came up with:
Warden::Manager.after_authentication do |user,auth,opts|
user.update_attribute(:currently_signed_in, true)
end
Warden::Manager.before_logout do |user,auth,opts|
user.update_attribute(:currently_signed_in, false)
end
This is what I came with to track users that are currently signed in.
I'm no expert but I believe the callbacks (hooks) are at the Warden level (Devise is built on top of Warden).
after_set_user and before_logout in Warden should do the trick for you but there are other options listed in Warden::Hooks
You can overwrite sign_in in your application controller like this
def sign_in(*args)
super(*args)
# do whatever you want here
token = current_user.authentications.where(provider: "facebook").first.token
facebook = Koala::Facebook::API.new(token)
session[:facebook] = facebook
end
Related
I am looking to set a secondary password by which I can authenticate a user for a login as from admin. The reason for this work around is the front end is a single page application.
Each user has been given a unique login_as string. now I need to configure Devise to compare the login_as if the password fails.
Any help is appreciated. I am of course open to an alternative solution if there is a better way.
Thanks.
This post from Duncan Robertson was very helpful in solving my issue. I essentially created an override strategy and called it in the devise.rb file. I had some concern regarding tampering with a large user base but it has proved successful. By adding a column to users named ":signin_as" and then setting it to a default unique string with a rake I then had what I needed to fallback on if the initial sign in failed.
the override strategy (config/initializers/auth_override.rb)
module Devise
module Strategies
class AuthOverride < Authenticatable
def custom_auth(user, signin_as)
if user[:signin_as] == signin_as
return true
else
return false
end
end
def authenticate!
user = User.find_by_email(email)
if user
if user.valid_password?(params[:password])
success!(user)
elsif custom_auth(user, params[:password])
success!(user)
else
fail
end
else
fail
end
end
end
end
end
including the strategy in devise (config/initializers/devise.rb)
config.warden do |manager|
manager.default_strategies(:scope => :user).unshift :auth_override
end
In the devise source code listed here:
https://github.com/plataformatec/devise/blob/master/lib/devise/controllers/helpers.rb
What exactly does line 56 do? In other words, I am not sure how devise determines whether a user is signed in.
It looks like it calls warden.authenticate with the scope of user(provided that user is what the model is)
Would I have to dive into the Warden codebase as well?
Devise delegates the work to warden. Warden checks if the username and password are valid.
Warden::Strategies.add(:my_strategy) do
def valid?
params[:username] && params[:password]
end
def authenticate!
u = User.find_by_username_and_password(
params[:username],
params[:password] # you should encrypt this. ;)
)
u.nil? ? fail!("Couldn't log in") : success!(u)
end
end
Warden::Manager.before_logout ?I have the following warden callback in config/initializers/devise.rb
Warden::Manager.before_logout do |user, auth, opts|
auth.session[:signout] = true
end
In my application controller I have this action, which is called by a before_filter
def user_logs_out
if session[:signout]
display_sign_out_popup = true
end
end
Then using my java script, I am trying to a show modal pop-up. But apparently, session[:logout] is not becoming true at all. Can I not access session variables set by
Warden::Manager.before_logout in application_controller.rb ?
My setup: Rails 3.0.9, Ruby 1.9.2, Devise 1.3.4, Warden 1.0.4
I'm trying to figure out if it possible to authenticate a custom strategy and not have to create a devise user in the process upon successful authentication. In my config.warden block, the authentication works fine but if I don't create a Devise user, I won't be authenticated. My ideal scenario requires me to either successfully authenticate against a 3rd party provider and sign into my app (using Devise without a corresponding Devise user record) or if I fail to authenticate, then try Devise standard login path.
Here is the devise.rb code snippet I got working but I have to create a devise user for the authentication to work, this is something I wish to avoid
config.warden do |manager|
manager.strategies.add(:custom_strategy) do
def valid?
params[:user] && params[:user][:email] && params[:user][:password]
end
def authenticate!
...perform authentication against 3rd party provider...
if successful_authentication
u = User.find_or_initialize_by_email(params[:user][:email])
if u.new_record?
u.app = 'blah'
u.save
end
success!(u)
end
end
end
manager.default_strategies(:scope => :user).unshift :custom_strategy
end
I realized the question is old but I saw it a couple of time when I was searching for a solution to similar thing so I decided to post the answer in case anyone in the future stumbles upon similar issue. Hope this will help!
I recently had to do similar thing -> had users in my database that were authenticated with some devise/warden strategies but had created another app that has to have access to some of the endpoints to my application. Basically I wanted to do a HMAC authentication.
But I didn't want to involve any user objects in that process and here is what I had to do (provided that you already have you custom strategy that authenticates incoming request without using user object)
create a fake user model that is used so that devise wont blow op. You dont have to create any database table for that
mine looked similar to below:
class Worker # no need to create a table for him
extend ActiveModel::Callbacks
extend Devise::Models
include ActiveModel::Validations
include Concerns::ObjectlessAuthenticatable
define_model_callbacks :validation
attr_accessor :id
def persisted
false
end
def initialize(id)
#id = id
end
def self.serialize_from_session(id)
self.new(id: id)
end
def self.serialize_into_session(record)
[record.id]
end
def self.http_authenticatable
false
end
end
then in devise initializer (/initializers/devise.rb) I've added separate authentication strategy like below:
...
config.warden do |manager|
manager.scope_defaults :user, :strategies => [
...strategies i was using for users
]
manager.scope_defaults :worker, :strategies => [:worker_authentication], store: false, action: 'unautenticated_worker'
manager.failure_app = CustomFailingApp
end
...
then in routes.rb I had to create a mapping for devise to use like so
devise_for :worker # you can pass some custom options here
then wherever I needed to authenticate the worker, not the user I just had to call (in the controller) authenticate_worker!
I would expect that this is against the design of devise where all actions are done using restful routes for a resource. That said, the comments in Warden's success! method say:
# Parameters:
# user - The user object to login. This object can be anything you have setup to serialize in and out of the session
So could you not change the object u to some other object that represents the user, like a plain old Hash?
I have a Rails app using Devise for authentication. Users belong to Dealers and I want to prevent users who belong to disabled dealers from being able to sign in.
Is there a straightforward way to extend Devise's authentication finder so that it will not include users from deleted dealers? Perhaps using a named scope on User?
Cheers
Tristan
Turns out all I needed to do was override my user model's find_for_authentication method:
class User < ActiveRecord::Base
...
# Intercept Devise to check if DealershipUser's Dealership is active
def self.find_for_authentication(conditions)
user = super
return nil if user.is_a?(DealershipUser) && user.dealership.deleted?
user
end
...
end
Find the user in the normal way by calling super.
I'm using STI so I check that the user is a DealershipUser and then check if the dealership is deleted (acts_as_paranoid).
Return the user.
This is a very specific solution for my scenario but you could override find_for_authentication however you like provided you return the user afterwards.
Searching Stackoverflow.com gave me this question/answer: Custom authentication strategy for devise
Basically, you have to implement a custom authentication strategy at Warden's level (that underlies Devise). For my project, I did the following:
In config/initializers/devise.rb:
Devise.setup do |config|
config.warden do |manager|
manager.default_strategies(:scope => :user).unshift :user_has_login_access
end
end
Warden::Strategies.add(:user_has_login_access) do
def valid?
# pass the commit parameter as 'login' or something like that, so that this strategy only activates when the user is trying to login
params[:commit] == 'login'
end
def authenticate!
u = User.find_by_email(params[:user][:email])
if u.can_login? # retrieves boolean value stored in the User model, set wherever
success! u
else
fail! "Account does not have login privilages."
end
end
end
You can read more about custom Warden strategies here: https://github.com/hassox/warden/wiki/Strategies
Hope that helps!