Подтвердить что ты не робот

Устанавливать ограничение на один сеанс на пользователя за раз

Мое приложение использует Rails 3.0.4 и Devise 1.1.7.

Я ищу способ предотвратить использование пользователями учетных записей, поскольку приложение является услугой, основанной на подписке. Я искал более недели, и я до сих пор не знаю, как реализовать решение. Я надеюсь, что кто-то выполнит решение и может указать мне в правильном направлении.

Решение (Спасибо всем за ваши ответы и понимание!)

В приложении 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

В session_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

В миграции 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
4b9b3361

Ответ 1

Вы не можете этого сделать.

  • Вы можете управлять IP-адресами пользователя, поэтому вы можете запретить присутствие пользователя из двух IP за раз. И вы можете связать логин и IP-адрес. Вы можете попытаться проверить города и другие данные геолокации через IP, чтобы заблокировать пользователя.
  • Вы можете установить файлы cookie для управления чем-то другим.

Но ничто из этого не гарантирует, что только один пользователь использует этот логин и что эти 105 IP со всего мира принадлежат не только одному уникальному пользователю, который использует прокси-сервер или что-то еще.

И последнее: вы никогда не нуждаетесь в этом в Интернете.

UPD

Тем не менее, я прошу ограничить использование нескольких пользователей одной и той же учетной записью одновременно, что, по моему мнению, должно быть возможным

Таким образом, вы можете сохранить некоторый токен, который будет содержать некоторые зашифрованные данные: IP + секретная строка + пользовательский агент + версия браузера пользователя + пользовательская ОС + любая другая личная информация: encrypt(IP + "some secret string" + request.user_agent + ...). А затем вы можете установить сеанс или файл cookie с этим токеном. И с каждым запросом вы можете его получить: если пользователь тот же? Использует ли он тот же браузер и ту же версию браузера из той же ОС и т.д.

Также вы можете использовать динамические токены: вы меняете токен на каждый запрос, поэтому только один пользователь может использовать систему за сеанс, поскольку каждый токен запроса будет изменен, другой пользователь будет выведен из системы, пока его токен будет истек.

Ответ 2

Этот драгоценный камень хорошо работает: https://github.com/phatworx/devise_security_extension

Добавить в Gemfile

gem 'devise_security_extension'

после установки пакета

rails g devise_security_extension:install

Затем запустите

rails g migration AddSessionLimitableToUsers unique_session_id

Отредактируйте файл миграции

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

Затем запустите

rake db:migrate

Отредактируйте файл приложения /models/user.rb

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

Готово. Теперь вход в другой браузер приведет к удалению любых предыдущих сеансов. Драгоценный камень фактически уведомляет пользователя о том, что он собирается убить текущий сеанс перед входом в систему.

Ответ 3

Что касается фактического внедрения в Devise, добавьте это в свою модель User.rb. Что-то вроде этого автоматически выйдет из системы (непроверено).

  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 

Ответ 4

Вот как я решил проблему с дублирующимся сеансом.

routes.rb

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

Контроллер 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

Модель пользователя Добавьте поле строки через миграцию с именем login_token

Это переопределяет контроллер Devise Session по умолчанию, но также наследует его. В новом сеансе маркер сеанса входа создается и хранится в login_token в модели User. В контроллере приложения мы вызываем check_concurrent_session, который выдает и перенаправляет current_user после вызова функции duplicate_session?.

Это не самый чистый способ сделать это, но он определенно работает.

Ответ 5

Я обнаружил, что решение в оригинальной публикации не работает для меня. Я хотел, чтобы первый пользователь вышел из системы и на странице входа. Кроме того, метод sign_out_and_redirect(current_user) работает не так, как я ожидал. Используя переопределение SessionController в этом решении, я модифицировал его для использования веб-сокетов следующим образом:

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

Убедитесь, что все веб-страницы подписываются на канал выписки и связывают его с тем же действием logout_subscribe_address. В моей заявке каждая страница также имеет кнопку "выйти", которая выдает клиенту через сеансовое действие "Уничтожить". Когда ответ веб-камеры запускается на веб-странице, он просто нажимает на эту кнопку - вызывается логика выписки и первый пользователь получает страницу с подписью.

Это решение также не требует skip_before_filter :check_concurrent_session и модели login_token, поскольку оно вызывает принудительный выход без предубеждений.

Для записи, devise_security_extension, как представляется, предоставляет функциональные возможности для этого. Он также устанавливает соответствующее предупреждение, предупреждающее первого пользователя о том, что произошло (я еще не понял, как это сделать).

Ответ 6

Отслеживайте IP-адреса uniq, используемые для каждого пользователя. Время от времени выполняйте анализ этих IP-адресов - обмен будет очевидным, если у одной учетной записи одновременно есть логины от разных интернет-провайдеров в разных странах. Обратите внимание, что просто наличие другого IP-адреса не является достаточным основанием для того, чтобы считать его общим - некоторые интернет-провайдеры используют прокси-серверы с циклическим циклом, поэтому каждый удар обязательно будет другим IP-адресом.

Ответ 7

Пока вы не можете надежно запретить пользователям делиться учетной записью, то, что вы можете сделать (я думаю), предотвращает одновременную регистрацию одного пользователя в одной учетной записи. Не уверен, что этого достаточно для вашей бизнес-модели, но она затрагивает множество проблем, обсуждаемых в других ответах. Я реализовал что-то, что в настоящее время находится в бета-версии, и, похоже, работает достаточно хорошо - есть некоторые примечания здесь