47 votes

Concevoir limite d'une session par utilisateur à la fois

Mon application est à l'aide de Rails 3.0.4 et de Concevoir 1.1.7.

Je suis à la recherche d'un moyen d'empêcher les utilisateurs de partager des comptes que l'application est un service sur abonnement. J'ai cherché pendant plus d'une semaine, et je ne sais toujours pas comment mettre en œuvre une solution. J'espère que quelqu'un a mis en œuvre une solution et peut me pointer dans la bonne direction.

Solution (Merci à vous tous pour vos réponses et votre perspicacité!)

En application du contrôleur.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

Dans session_controller qui remplace Concevoir des Séances de contrôleur:

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

Dans la 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

31voto

scarver2 Points 2605

Ce joyau qui fonctionne bien: https://github.com/phatworx/devise_security_extension

Ajouter au Gemfile

gem 'devise_security_extension'

après bundle install

rails g devise_security_extension:install

Ensuite, exécutez

rails g migration AddSessionLimitableToUsers unique_session_id

Modifier le fichier de migration

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

Ensuite, exécutez

rake db:migrate

Modifier votre app/models/user.rb fichier

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

Fait. Maintenant connecté à partir d'un autre navigateur va tuer toutes les sessions précédentes. Le joyau réelle avertit l'utilisateur qu'il est sur le point de tuer une session en cours avant de vous connecter.

10voto

fl00r Points 41855

Vous ne pouvez pas le faire.

  • Vous pouvez contrôler les adresses IP de l'utilisateur, de sorte que vous pouvez prévenir de la présence de l'utilisateur à partir de deux IP à la fois. Et vous pouvez lier la connexion et la propriété intellectuelle. Vous pouvez essayer de vérifier les villes et les autres données de géolocalisation par IP à bloquer l'utilisateur.
  • Vous pouvez définir des cookies pour contrôler quelque chose d'autre.

Mais rien de cela ne garantie que seul un utilisateur utilise cette connexion, et que ceux 105 IP de tous les coins du monde n'appartient pas à un seul et unique utilisateur, qui utilise un Proxy ou quoi que ce soit.

Et la dernière: vous n'avez jamais besoin de cela dans l'Internet.

UPD

Cependant, ce que je demande est à propos de la limitation à plusieurs utilisateurs d'utiliser le même compte en même temps je me sens devrait être possible

De sorte que vous pouvez stocker quelques jeton, qui contiennent des données chiffrées: IP + chaîne secrète + user agent + navigateur de l'utilisateur version + système d'exploitation + autres infos personnelles: encrypt(IP + "some secret string" + request.user_agent + ...). Et puis vous pouvez définir une session ou un cookie avec le jeton. Et avec chaque demande, vous pouvez le récupérer: si l'utilisateur est le même? Est-il en utilisant le même navigateur et la même version de navigateur à partir du même système d'exploitation, etc.

Aussi vous pouvez utiliser la dynamique des jetons: vous changez de jeton de chaque demande, de sorte qu'un utilisateur pourrait utiliser le système par session, parce que chaque jeton de demande sera changé, un autre utilisateur sera déconnecté aussi loin que son jeton sera expiré.

2voto

Dex Points 4871

Dans la mesure où effectivement mise en œuvre dans l'élaboration, à l'ajouter à vos Utilisateurs.rb modèle. Quelque chose comme cette session automatiquement (non testé).

  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 

1voto

davidm Points 1

J'ai trouvé que la solution dans le message d'origine n'a pas assez de travail pour moi. Je voulais que le premier utilisateur d'être connecté et d'une page d'ouverture de session présenté. Aussi, l' sign_out_and_redirect(current_user) méthode ne semble pas fonctionner de la manière dont je m'attends. À l'aide de la SessionsController remplacer dans cette solution je l'ai modifié pour utiliser les websockets comme suit:

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

Assurez-vous que toutes les pages web abonnez-vous à la signout canal et le lier à la même logout_subscribe_address action. Dans mon application, chaque page possède également un "signe" du bouton, qui signe le client via le dispositif de la session de Détruire l'action. Lorsque le websocket réponse est déclenché dans la page web, il suffit simplement de cliquer sur ce bouton - le signout logique est invoquée et le premier utilisateur est présenté avec la page de connexion.

Cette solution ne nécessite pas l' skip_before_filter :check_concurrent_session et le modèle d' login_token car il déclenche la déconnexion forcée sans préjudice.

Pour l'enregistrement, l' devise_security_extension semble fournir la fonctionnalité de le faire. Il met aussi en place d'un avertissement et d'alerte (le premier utilisateur à propos de ce qui s'est passé (je n'ai pas compris comment le faire encore).

0voto

Marc B Points 195501

Garder une trace de uniq IPs utilisées par l'utilisateur. Maintenant et puis, exécutez une analyse sur les IPs de partage serait évident si un seul compte a connexions simultanées à partir de plusieurs fournisseurs d'accès dans les différents pays. Notez qu'il suffit d'avoir une adresse IP différente n'est pas un motif suffisant pour considérer partagés, certains Fai utilisent la méthode round-robin des procurations, de sorte que chaque coup serait forcément une adresse IP différente.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X