Set a limit on one session per user at a time

My application uses Rails 3.0.4 and Devise 1.1.7.

I am looking for a way to prevent users from using accounts, as the application is a subscription-based service. I searched for over a week, and I still don't know how to implement the solution. I hope someone fulfills the decision and can point me in the right direction.

Solution (Thank you all for your answers and understanding!)

In controller.rb application

before_filter :check_concurrent_session def check_concurrent_session if is_already_logged_in? sign_out_and_redirect(current_user) end end def is_already_logged_in? current_user && !(session[:token] == current_user.login_token) end 

In session_controller, which overrides the Devise Sessions controller:

 skip_before_filter :check_concurrent_session def create super set_login_token end private def set_login_token token = Devise.friendly_token session[:token] = token current_user.login_token = token current_user.save end 

In migration AddLoginTokenToUsers

 def self.up change_table "users" do |t| t.string "login_token" end end def self.down change_table "users" do |t| t.remove "login_token" end end 
+42
ruby-on-rails ruby-on-rails-3 session devise
Aug 15 '11 at 18:23
source share
7 answers

You cannot do this.

  • You can manage a user's IP addresses, so you can prevent a user from two IPs from being present at a time. And you can associate login and IP address. You can try to check cities and other geolocation data via IP to block the user.
  • You can set cookies to control something else.

But none of this guarantees that only one user uses this login and that these 105 IPs from all over the world belong to more than one unique user who uses a proxy server or something else.

One last thing: you never need this on the Internet.

UPD

However, I ask you to limit the use of multiple users to the same account at the same time, which, in my opinion, should be possible

Thus, you can save some token that will contain some encrypted data: IP + secret line + user agent + version of the user's browser + user OS + any other personal information: encrypt(IP + "some secret string" + request.user_agent + ...) . And then you can set up a session or cookie with this token. And with each request you can get it: if the user is the same? Does it use the same browser and the same browser version from the same OS, etc.

You can also use dynamic tokens: you change the token for each request, so only one user can use the system per session, since each request token will be changed, the other user will be logged out of the system until its token expires.

+9
Aug 15 '11 at 18:34
source share
— -

This gem works well: https://github.com/phatworx/devise_security_extension

Add to Gemfile

 gem 'devise_security_extension' 

after installing the package

 rails g devise_security_extension:install 

Then run

 rails g migration AddSessionLimitableToUsers unique_session_id 

Edit the migration file

 class AddSessionLimitableToUsers < ActiveRecord::Migration def change add_column :users, :unique_session_id, :string, limit: 20 end end 

Then run

 rake db:migrate 

Edit the application file /models/user.rb

 class User < ActiveRecord::Base devise :session_limitable # other devise options ... rest of file ... end 

Done. Logging into another browser will now delete any previous sessions. The gem actually notifies the user that he is about to kill the current session before entering the system.

+26
Aug 09 '13 at 1:15
source share

Regarding the actual implementation in Devise, add this to your User.rb model. Something like this will automatically log out (unchecked).

  def token_valid? # Use fl00rs method of setting the token session[:token] == cookies[:token] end ## Monkey Patch Devise methods ## def active_for_authentication? super && token_valid? end def inactive_message token_valid? ? super : "You are sharing your account." end 
+2
Aug 16 2018-11-11T00:
source share

This is how I solved the duplicate session issue.

routes.rb

  devise_for :users, :controllers => { :sessions => "my_sessions" } 

My_sessions controller

 class MySessionsController < Devise::SessionsController skip_before_filter :check_concurrent_session def create super set_login_token end private def set_login_token token = Devise.friendly_token session[:token] = token current_user.login_token = token current_user.save(validate: false) end end 

application_controller

  def check_concurrent_session if duplicate_session? sign_out_and_redirect(current_user) flash[:notice] = "Duplicate Login Detected" end end def duplicate_session? user_signed_in? && (current_user.login_token != session[:token]) end 

User Model Add a row field through the migration named login_token

This overrides the default Devise Session controller, but also inherits it. In a new session, a login session token is created and stored in login_token in the User model. In the application controller, we call check_concurrent_session , which issues and redirects current_user after calling the duplicate_session? function duplicate_session? .

This is not the cleanest way to do this, but it definitely works.

+2
Sep 22 '14 at 23:51
source share

I found that the solution in the original publication does not work for me. I wanted the first user to log out and on the login page. In addition, the sign_out_and_redirect(current_user) method does not work as I expected. Using the SessionController override in this solution, I modified it to use web sockets as follows:

 def create super force_logout end private def force_logout logout_subscribe_address = "signout_subscribe_response_#{current_user[:id]}" logout_subscribe_resp = {:message => "#{logout_subscribe_address }: #{current_user[:email]} signed out."} WebsocketRails[:signout_subscribe].trigger(signout_subscribe_address, signout_subscribe_resp) end end 

Make sure that all web pages subscribe to the logout_subscribe_address channel and associate it with the same logout_subscribe_address action. In my application, each page also has a "exit" button, which gives the client through the "Destroy" session action. When a webcam response is launched on a web page, it simply clicks on this button - the statement logic is called up and the first user receives a page with a signature.

This solution also does not require skip_before_filter :check_concurrent_session and the login_token model, as it causes a forced exit without prejudice.

For the record, devise_security_extension seems to provide functionality for this. It also sets up an appropriate warning warning the first user about what happened (I haven't figured out how to do this yet).

+1
Jun 06 '14 at 20:08
source share

Track the uniq IP addresses used for each user. From time to time, analyze these IP addresses - the exchange will be obvious if one account at the same time has logins from different Internet providers in different countries. Please note that simply having a different IP address is not sufficient reason to consider it common - some ISPs use proxy servers with a cyclic cycle, so each hit will necessarily be a different IP address.

0
Aug 15 '11 at 18:31
source share

While you cannot reliably prevent users from sharing an account, what you can do (I think) prevents the simultaneous registration of one user in one account. Not sure if this is enough for your business model, but it does touch on a lot of the issues discussed in other answers. I implemented something that is currently in beta and seems to work quite well - there are some notes here

0
Aug 16 2018-11-11T00:
source share



All Articles