Authlogic: Restricting simultaneous sessions
Anyway, we're using the splendid Authlogic plug-in for all the authentication duties and while it does many things very well it doesn't have a built-in way to restrict simultaneous logins. I asked around and got a couple of tips on what might work and how I might proceed. It was a simple process but after several others had the same problem I thought I would formalize the "solution" in a blog post in hopes that it might help someone else in the future.
- Step One - Add a place to store a session key
# add_session_key_to_users.rb
This gives us a place to store a "session_key" value that changes every time a user logs in.
class AddSessionKeyToUsers < ActiveRecord::Migration
def self.up
add_column :users, :session_key, :string
end
def self.down
remove_column :users, :session_key
end
end - Step Two - Insert the "session_key" on login
# user_sessions_controller.rb
def create
...
if @user_session.save
# Save the session ID to detect simultaneous login attempts
@user_session.record.session_key = session[:session_id]
@user_session.record.save!
...
end
end
What this does is forces the session_id to be saved to the User model each time a user logs into the site. We'll check this value later to make sure the session hasn't changed. I'm using the session_id here as a "unique" value but it could be anything you want; timestamp, IP address, etc... - Step Three - Make sure the user is unique
# application_controller.rb
def current_user
...
# Prevent simultaneous logins
if @current_user && @current_user.session_key != session[:session_id]
flash[:notice] = 'Access denied. Simultaneous logins detected.'
current_user_session.destroy
end
end
Here is where the rubber meets the road, so to speak. In Authlogic, the current_user method is accessed on every page request so it is the perfect place to check for duplicate user sessions. We simple verify that the session_id in the users cookie is the same one in the database. If they are different we destroy the session and update the flash message.
This is a pretty simple little hack but it seems to work OK. One "problem" that I have noticed is that while the session is immediately destroyed the current request continues unabated. This means that the two users could possibly perform two actions at the same time, but it shouldn't be a problem. Another side effect of this technique is that the last user to log in always gets the session. This might be a problem for you but it wasn't for my project.