with tutorial framework español djangoproject desde con cero applications ruby-on-rails ruby-on-rails-3 session devise

ruby on rails - tutorial - Diseñar límite de una sesión por usuario a la vez



tutorial django (7)

Mi aplicación usa Rails 3.0.4 y Devise 1.1.7.

Estoy buscando una forma de evitar que los usuarios compartan cuentas, ya que la aplicación es un servicio basado en suscripción. He estado buscando durante más de una semana, y todavía no sé cómo implementar una solución. Espero que alguien haya implementado una solución y pueda orientarme en la dirección correcta.

Solución (¡Gracias a todos por sus respuestas y comprensión!)

En la aplicación 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

En session_controller que anula el controlador 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

En migración 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


Así es como resolví el problema de la sesión duplicada.

routes.rb

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

controlador 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

Modelo de usuario Agregue un campo de cadena a través de una migración llamada login_token

Esto anula el controlador predeterminado Devise Session, pero hereda de él también. En una nueva sesión, se crea un token de sesión de inicio de sesión y se almacena en login_token en el modelo de Usuario. En el controlador de la aplicación llamamos a check_concurrent_session que check_concurrent_session la check_concurrent_session y redirige al check_concurrent_session después de llamar a la duplicate_session? función.

No es la forma más limpia de hacerlo, pero definitivamente funciona.


Descubrí que la solución en la publicación original no funcionaba para mí. Quería que el primer usuario se desconectara y se presentara una página de inicio de sesión. Además, el sign_out_and_redirect(current_user) no parece funcionar de la manera que esperaría. Al utilizar la anulación de SessionsController en esa solución, la modifiqué para usar websockets de la siguiente manera:

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

Asegúrese de que todas las páginas web se suscriban al canal de suscripción y lo vinculen a la misma acción logout_subscribe_address . En mi aplicación, cada página también tiene un botón de "cerrar sesión", que cierra la sesión del cliente a través de la sesión Destruir acción de la sesión. Cuando se activa la respuesta de websocket en la página web, simplemente hace clic en este botón: se invoca la lógica de cierre de sesión y se presenta al primer usuario con la página de inicio de sesión.

Esta solución tampoco requiere el skip_before_filter :check_concurrent_session y el modelo login_token ya que desencadena el cierre de sesión forzado sin perjuicio.

Para el registro, la devise_security_extension parece proporcionar la funcionalidad para hacer esto también. También pone una alerta apropiada advirtiendo al primer usuario sobre lo que sucedió (aún no he descubierto cómo hacerlo).


En cuanto a implementarlo realmente en Devise, agregue esto a su modelo User.rb. Algo como esto los desconectará automáticamente (no probado).

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


Esta gema funciona bien: https://github.com/phatworx/devise_security_extension

Agregar a Gemfile

gem ''devise_security_extension''

después de la instalación del paquete

rails g devise_security_extension:install

Entonces corre

rails g migration AddSessionLimitableToUsers unique_session_id

Edite el archivo de migración

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

Entonces corre

rake db:migrate

Edite su archivo de aplicaciones / modelos / user.rb

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

Hecho. Ahora iniciar sesión desde otro navegador matará las sesiones anteriores. La gema real notifica al usuario que está a punto de matar una sesión actual antes de iniciar sesión.


Mantenga un registro de direcciones IP uniq utilizadas por usuario. De vez en cuando, realice un análisis de esas IP: el intercambio sería obvio si una sola cuenta tiene inicios de sesión simultáneos de diferentes ISP en diferentes países. Tenga en cuenta que el simple hecho de tener una dirección IP diferente no es motivo suficiente para considerarlo compartido: algunos ISP utilizan proxies round-robin, por lo que cada hit necesariamente sería una dirección IP diferente.


No puedes hacerlo

  • Puede controlar las direcciones IP del usuario, por lo que puede evitar la presencia de usuarios de dos IP a la vez. Y puede vincular el inicio de sesión y la IP. Puede intentar consultar las ciudades y otros datos de geolocalización a través de IP para bloquear al usuario.
  • Puede establecer cookies para controlar otra cosa.

Pero nada de esto garantizará que solo un usuario use este inicio de sesión, y que esos 105 IP de todo el mundo no pertenezcan a un solo usuario único, que use Proxy o lo que sea.

Y el último: nunca necesitas esto en Internet.

UPD

Sin embargo, lo que estoy preguntando es sobre la limitación de que múltiples usuarios usen la misma cuenta simultáneamente, lo cual creo que debería ser posible.

Así que puedes almacenar algunos tokens, que contendrán algunos datos cifrados: IP + cadena secreta + agente de usuario + versión del navegador del usuario + SO del usuario + cualquier otra información personal: encrypt(IP + "some secret string" + request.user_agent + ...) . Y luego puede establecer una sesión o cookie con ese token. Y con cada solicitud puede buscarla: si el usuario es el mismo? Está utilizando el mismo navegador y la misma versión de navegador del mismo sistema operativo, etc.

También puedes usar tokens dinámicos: cambias el token a cada solicitud, por lo que solo un usuario puede usar el sistema por sesión, ya que cada token de solicitud se cambiará, otro usuario cerrará sesión hasta que su token expire.


Si bien no puede evitar de manera confiable que los usuarios compartan una cuenta, lo que usted puede hacer (creo) es evitar que más de un usuario inicie sesión al mismo tiempo en la misma cuenta. No estoy seguro si esto es suficiente para su modelo de negocio, pero soluciona muchos de los problemas discutidos en las otras respuestas. Implementé algo que actualmente está en beta y parece funcionar razonablemente bien. here hay algunas notas.