Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Devise - Invalidate user session if the same user logs in from a different browser/machine

I have a scenario where i need to restrict users from having only one active session at a time. Mine is a rails3 application and uses devise for authentication. I'm interested in keeping only the latest user session active. i.e., if a user logs in while there is another session active for the same username, i want to inactivate the older session and allow the recent one. Is there a way, in devise, to get hold of user sessions and invalidate them?

like image 811
Kalarani Avatar asked Sep 09 '11 09:09

Kalarani


2 Answers

You can track a particular user's session by storing a unique token specific to that user in the database.

Create a migration to add the field for storing the token. I assume the devise model is User.

class AddSignInTokenToUsers < ActiveRecord::Migration
  def change
    add_column :users, :current_sign_in_token, :string
  end
end

Add the following code to application_controller.rb

class ApplicationController < ActionController::Base
  before_filter :invalidate_simultaneous_user_session, :unless => Proc.new {|c| c.controller_name == 'sessions' and c.action_name == 'create' }

  def invalidate_simultaneous_user_session
    sign_out_and_redirect(current_user) if current_user && session[:sign_in_token] != current_user.current_sign_in_token
  end

  def sign_in(resource_or_scope, *args)
    super
    token = Devise.friendly_token
    current_user.update_attribute :current_sign_in_token, token
    session[:sign_in_token] = token
  end
end

sign_in(resource_or_scope, *args) is a devise hook that will be called every time the user logs in.

invalidate_simultaneous_user_session will log out the current user if another instance of the current user logs in. This will ensure that only one session is active for a user at any instance of time.

invalidate_simultaneous_user_session filter should be skipped for the user login action to update the newly logged in user's token. I am not happy with using a Proc to skip the filter based on controller name and action. If you have already overridden devise's sessions_controller, then include skip_before_filter :check_simultaneous_user_session inside that controller and you can get rid of the Proc!

Hope this helps..

like image 190
dexter Avatar answered Jan 04 '23 01:01

dexter


For updated devise for rails 4, you may change the code according to this

http://pastebin.com/p6mvC8T3

like image 31
James Tan Avatar answered Jan 03 '23 23:01

James Tan