Any difference between 'authenticate_user!', 'user_signed_in?', & 'if current_user'? - ruby-on-rails

This may be a dumb question, but I'm finishing up this app using Devise & am just wondering, is there any significant difference between authenticate_user!, user_signed_in?, & if current_user? If so, then in what cases would I not use one or the other?
Thanks

Not sure what you mean by 'significant difference', all these do different things:
authenticate_user! # Signs user in or redirect
user_signed_in? # Checks whether there is a user signed in or not
current_user # Current signed in user
Source: https://github.com/plataformatec/devise/blob/master/lib/devise/controllers/helpers.rb

Just reading the variable names you can see they are not the same thing.
authenticate_user!
This is a method to check user authentication, i.e., check if login and password matches.
user_signed_in?
This method checks if a user is signed in on the application. If there are any data inside the session that tells the application a user is signed in.
current_user
This gets the user that is logged in the application.

Related

Rails block user account if failed test during registration process

I want to build User registration flow where user signup to the blog_app and after account confirmation (via email link) he/she will be able to log in but have no ability to access their posts if he/she doesn't pass Legal Test (after the User account is confirmed, they should be presented with the Legal Test before they can do anything else, user needs to pass the test only once).
For authentication I'm using Devise gem.
I'm wondering should I use some Devise build-in module such case? or should I create additional DB column in Users table with status e.g. status: 'passed' or status: 'faild' and use pundit policy to block access in case User didn't passed the Legal Test?
Yes, you should an authorization gem like Pundit to manage authorization.
To accomplish something like this in Devise you would need separate roles for a "passed user" and a "failed user". It will quickly get messy and confusing as it's really not what it's meant for.
Using an authorization gem like Pundit is the way to go for your use case.
Yes, you will have to add a new column like status where you store the status and then override the devise's active_for_authentication? method so that the user is not allowed to login if he/she is marked as failed/banned:
def active_for_authentication?
super && self.status != 'failed'
end

Rails 5 Geolocation with Clearance

I'm currently using Clearance for authentication. As part of the login process I want to ensure that I have a location for the user (stored in the session).
My question is how to do this in the context of clearance? Ideally I only want to perform the lookup on login (to save network traffic / API calls). If I can't locate a user then I'll deny login.
I was thinking of using a guard but I don't seem to have access to request.ip or session which is a bit of a deal breaker. I was also trying to avoid redirecting to a URL that only does the geolocation and then redirects again.
Anybody have ideas on a nice model on how to make this work? Thanks!
Sign in guards are mostly intended for processes that will prevent or allow sign in. I don't think they are a good fit here. For this use case, I would suggest overriding sign_in, which is generally mixed in to ApplicationController
def sign_in(user, &block)
super
if signed_in?
UserGeocoder.call(current_user)
end
end

Devise: How to use remember_me cookie after user sign out?

I'm working on a Rails 4.2 Application and using devise gem for authentication.
For remember_me feature, devise generates a cookie remember_user_token which gets destroy after sign_out.
Is there a way such that Devise should not destroy remember_user_token ?
I tried to false the below config in the initializer
config.expire_all_remember_me_on_sign_out = false
But it didn't help.
I need that cookie after sign-out such that it will populate the login form.
Please help.
Thanks
Coupling authentication with form pre-filling isn't necessarily a good idea. You can store the login in a cookie upon successful login. You can override the create method in your SessionsController, call super to call Devise::SessionsController#create and pass it a block. The block will be executed after a successful log in and will receive the user as a parameter.
class SessionsController < Devise::SessionsController
def create
super do |user|
cookies[:login] = user.login
end
end
end
Here is the low down on cookie store. First off, everything in a cookie is there permanently once it's set or until the user deletes the cookie manually somehow. This means, that if you set user_id and user_group_id, it's there for good in the cookie until updated or deleted. This is different from a session since the session is like ram on a computer, once the browser is closed, the session closes with it as well as all of it's data.
So, this means that when you log out your user, you need to specify that their cookie empties anything you don't wan't it to have. When your user logs in, you set anything that you want the user to have while they are logged in. So, since the session and cookie are separate things completely, they never interact together unless you choose to make them. So your session will never dump its self into the cookie store unless you make it do that.
Every time your users go to your site, you could have a single handshake that makes sure that the cookie matches the db if necessary. Otherwise, you could have differing data what only gets updated on login or what not and without the handshake, the user would have to keep logging in to make sure they are still valid which defeats the purpose of having a cookie in the first place.
The downside of client side cookie storage is security concerns. Depending on how you use the cookie to store data, a person could hijack somebodies cookie on your site and pretend they are them. This can be avoided by careful design, but just assume that whatever is in your cookie store is fair game to everybody so use it carefully and for only non secret data.
Hope this helps!

Sign out specific user with Devise in Rails

I have Devise for user authentication.
I want to sign out a user with a specific id.
in my controller
def exit
#user = User.find(5)
sign_out(#user) # this line here signs out the current_user
end
The sign out command of devise, even though I pass the #user, it signs out the current_user.
How can I select a user from the database and sign him out with the devise commands?
I am assuming this is part of some admin module, where you want to sign out a particular user.
However, this is not easy to solve. Whether or not a user is signed in or not is stored in the session. So to sign out another user, you would have to have access to its session.
Note: afaik the sign_out method only works in the current session, or maybe through warden (do not know warden well enough) it could extend to all sessions this current server has ever touched. However: if you use passenger, or some form of rails server cluster (which is pretty common), afaik this will not work. I would be interested to hear otherwise, with some explanation :) The sign_out uses the given parameter to determine the scope to sign out from in (afaik) the current session.
So what we generally did was add a kind of emergency button to sign out all users: which destroys all sessions. Note this is of course only possible if you use some database or document-store backed session-store.
Alternatively you could open all sessions, and look for the correct session (for your user), and then destroy those sessions.
To read data from a specific session in stored in activerecord, you can write the following:
#session = ActiveRecord::Base.connection.select_all( "SELECT * FROM sessions WHERE session_id = '#{sess_id}'" )
Marshal.load(ActiveSupport::Base64.decode64(#session.data))
There are alternative approaches:
use Timeoutable module, and force a timeout for a user?
if you use Rememberable you could do #user.forget_me, but I am not sure that this actually affects the current session?
from the device api doc http://rubydoc.info/github/plataformatec/devise/master/Devise/Controllers/SignInOut#sign_out-instance_method the sign_out(#user) method should works. Is it possible that the current_user by chance has the id 5?

Do Rails' Devise, AuthLogic, Restful Authentication all use the same method names or mechanism such as current_user and session[:user_id]?

I see similar usage all the time, even in Rails guide such as http://guides.rubyonrails.org/security.html
For example, current_user returns the current logged in user, logged_in? returns whether there is a logged in user, #current_user stores
the logged in user (so no need to look into DB again), session[:user_id] stores the user id
of the current logged in user so as to know what the logged in user is on a second or later webpage request (need to look into DB), remember_token is the users table field to check against cookies[:auth_token],
so as to remember the user even when the user closes the browser (so the session ends and session cookie disappears)
Do Devise, AuthLogic, and Restful Authentication all use these names / mechanism?
I am not sure but I think they don't because restful uses logged_in? while devise uses user_signed_in? where user can be replaced by your model...

Resources