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




4 Answers

Non puoi farlo.

  • È possibile controllare gli indirizzi IP dell'utente, in modo da impedire la presenza dell'utente da due IP alla volta. E puoi associare il login e l'IP. Puoi provare a controllare le città e altri dati di geolocalizzazione tramite IP per bloccare l'utente.
  • È possibile impostare i cookie per controllare qualcos'altro.

Ma nulla di tutto ciò garantirà che solo un utente utilizzi questo login e che quei 105 IP di tutto il mondo non appartengano a un solo utente unico, che utilizza Proxy o altro.

E l'ultimo: non hai mai bisogno di questo in Internet.

UPD

Tuttavia, quello che sto chiedendo è di limitare l'utilizzo simultaneo di più utenti dello stesso account che ritengo dovrebbe essere possibile

Quindi puoi memorizzare qualche token, che conterrà alcuni dati crittografati: IP + stringa segreta + agente utente + versione browser utente + sistema operativo utente + qualsiasi altra informazione personale: encrypt(IP + "some secret string" + request.user_agent + ...) . E poi puoi impostare una sessione o un cookie con quel token. E con ogni richiesta puoi recuperarlo: se l'utente è lo stesso? Sta utilizzando lo stesso browser e la stessa versione del browser dello stesso sistema operativo, ecc.

Puoi anche utilizzare token dinamici: cambia token ogni richiesta, in modo che solo un utente possa utilizzare il sistema per sessione, poiché ogni token di richiesta verrà modificato, un altro utente verrà disconnesso fino a quando il suo token sarà scaduto.

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



Per quanto effettivamente implementandolo in Devise, aggiungilo al tuo modello User.rb. Qualcosa di simile li registrerà automaticamente (non testati).

  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 



Ho trovato che la soluzione nel post originale non ha funzionato per me. Volevo che il primo utente fosse disconnesso e che fosse presentata una pagina di accesso. Inoltre, il sign_out_and_redirect(current_user) non sembra funzionare come mi aspetterei. Usando l'override di SessionsController in quella soluzione, l'ho modificato per usare websockets come segue:

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

Assicurarsi che tutte le pagine Web si abbonino al canale di signout e colleghino alla stessa azione logout_subscribe_address . Nella mia applicazione, ogni pagina ha anche un pulsante 'disconnessione', che firma il client tramite la sessione di sviluppo. Distruggi l'azione. Quando la risposta websocket viene attivata nella pagina Web, fa semplicemente clic su questo pulsante: la logica di signout viene richiamata e il primo utente viene presentato con la pagina di accesso.

Questa soluzione inoltre non richiede skip_before_filter :check_concurrent_session e il modello login_token poiché attiva il logout forzato senza pregiudizio.

Per la cronaca, sembra che devise_security_extension fornisca la funzionalità anche per questo. Inserisce anche un avviso appropriato che avverte il primo utente di ciò che è accaduto (non ho ancora capito come farlo).




Sebbene non sia possibile impedire in modo affidabile agli utenti di condividere un account, ciò che puoi fare (penso) è impedire che più di un utente si colleghi contemporaneamente allo stesso account. Non sono sicuro se questo è sufficiente per il tuo modello di business, ma aggira molti dei problemi discussi nelle altre risposte. Ho implementato qualcosa che è attualmente in beta e sembra funzionare abbastanza bene - ci sono alcune note here




Related