[ruby-on-rails] Definire il limite di una sessione per utente alla volta


Answers

Questa gemma funziona bene: https://github.com/phatworx/devise_security_extension

Aggiungi a Gemfile

gem 'devise_security_extension'

dopo l'installazione del pacchetto

rails g devise_security_extension:install

Quindi corri

rails g migration AddSessionLimitableToUsers unique_session_id

Modifica il file di migrazione

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

Quindi corri

rake db:migrate

Modifica il tuo file app / models / user.rb

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

Fatto. Ora l'accesso da un altro browser ucciderà qualsiasi sessione precedente. La gemma avvisa l'utente che sta per uccidere una sessione corrente prima di effettuare il login.

Question

La mia app utilizza Rails 3.0.4 e Devise 1.1.7.

Sto cercando un modo per impedire agli utenti di condividere account poiché l'app è un servizio basato su abbonamento. Ho cercato per oltre una settimana, e ancora non so come implementare una soluzione. Spero che qualcuno abbia implementato una soluzione e possa indicarmi la giusta direzione.

Soluzione (grazie a tutti per le vostre risposte e intuizioni!)

Nell'applicazione controller.rb

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 che sovrascrive il controller Devise Sessions:

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

Nella migrazione 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



Tieni traccia degli uniq IP utilizzati per utente. Di tanto in tanto, esegui un'analisi su quegli IP: la condivisione sarebbe ovvia se un singolo account avesse accessi simultanei da diversi ISP in diversi paesi. Si noti che il semplice fatto di avere un IP diverso non è un motivo sufficiente per considerarlo condiviso - alcuni ISP utilizzano proxy round robin, quindi ogni hit dovrebbe essere necessariamente un IP diverso.




Ecco come ho risolto il problema della duplicazione della sessione.

routes.rb

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

controller my_sessions

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

Modello utente Aggiungi un campo stringa tramite una migrazione denominata login_token

Questo sovrascrive il controller predefinito di Devise Session ma eredita anche da esso. In una nuova sessione un token di sessione di accesso viene creato e memorizzato in login_token sul modello Utente. Nel controller dell'applicazione chiamiamo check_concurrent_session che firma fuori e reindirizza l'utente current_user dopo aver chiamato il duplicate_session? funzione.

Non è il modo più pulito per farlo, ma funziona sicuramente.




Related