Ограничение количества одновременных логинов (сеансов) с Rails и Devise? [Дубликат]

Я иногда использую это поведение как альтернативу следующему шаблону:

singleton = None

def use_singleton():
    global singleton

    if singleton is None:
        singleton = _make_singleton()

    return singleton.use_me()

Если singleton используется только use_singleton, мне нравится следующий шаблон в качестве замены:

# _make_singleton() is called only once when the def is executed
def use_singleton(singleton=_make_singleton()):
    return singleton.use_me()

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

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

42
задан John 16 August 2011 в 22:26
поделиться

7 ответов

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

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

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

И последнее: вам никогда не понадобится это в Интернет.

UPD

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

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

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

9
ответ дан fl00r 21 August 2018 в 23:46
поделиться
  • 1
    Совместное использование учетной записи, с которой я согласен, невозможно остановить. Однако то, о чем я прошу, заключается в том, чтобы ограничить одновременное использование одной учетной записью нескольких пользователей, что, по моему мнению, должно быть возможным. – John 16 August 2011 в 00:08
  • 2
    @ user825641, обновлен answe – fl00r 16 August 2011 в 09:34
  • 3
    Спасибо за ваше обновление fl00rs. Сейчас я использую простой токен, пока не получу его работу, но я ценю ваш подробный ответ. – John 16 August 2011 в 17:59
  • 4
    Вы никогда не сможете этого сделать. Вы можете это сделать. Двойное отрицание здесь. – Kenny Meyer 17 September 2011 в 16:55
  • 5
    @KennyMeyer не только это, это значит, что невозможно это не сделать :) – Jon Cairns 23 October 2014 в 14:10

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

0
ответ дан chrispanda 21 August 2018 в 23:46
поделиться

Я обнаружил, что решение в оригинальной публикации не работает для меня. Я хотел, чтобы первый пользователь вышел из системы и на странице входа. Кроме того, метод 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, как представляется, обеспечивает функциональность, чтобы сделать это. Он также устанавливает соответствующее предупреждение, предупреждающее первого пользователя о том, что произошло (я еще не понял, как это сделать).

1
ответ дан davidm 21 August 2018 в 23:46
поделиться

Что касается фактического внедрения в 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 
2
ответ дан Dex 21 August 2018 в 23:46
поделиться
  • 1
    Привет, спасибо за ответ. Я пытаюсь полностью понять ваше решение в сочетании с этажами. Я не нашел active_for_authentication? но я нашел активный? который, я считаю, служит той же цели. Я немного потерял, когда в игру вступают файлы cookie [: токен]? Вы просто устанавливаете токен в файле cookie или сохраняете его в базе данных. Я обновил свой вопрос, чтобы отразить свой текущий прогресс. Благодарю. – John 16 August 2011 в 17:49

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

0
ответ дан Marc B 21 August 2018 в 23:46
поделиться
  • 1
    Я больше беспокоюсь о том, что пользователи используют учетную запись в организации, а не в разных странах. Будет ли решение uniq IP жизнеспособным, если совместно используемая учетная запись принадлежит нескольким пользователям в одной сети? – John 15 August 2011 в 19:58
  • 2
    Возможно, если у них нет шлюза NAT, который заставил бы всех пользователей появляться под одним (или очень немногим IP-адресами). – Marc B 15 August 2011 в 19:59

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

routes.rb

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

my_sessions controller

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 токен сеанса входа. В контроллере приложения мы вызываем check_concurrent_session, который выдает и перенаправляет current_user после вызова функции duplicate_session?.

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

2
ответ дан nulltek 21 August 2018 в 23:46
поделиться

Этот драгоценный камень хорошо работает: 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 file

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

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

27
ответ дан scarver2 21 August 2018 в 23:46
поделиться
  • 1
    Похоже, у этого есть эта функция, но с того момента, когда я написал это, он несовместим с Rails 4 и Ruby 2.0 – Mason 29 December 2013 в 03:45
  • 2
    Работает для меня на Rails 4.2 & amp; & amp; рубин 2.2.0 – Matthew Chan 19 November 2015 в 09:13
  • 3
    Работает на Rails 5.0.2 и Ruby 2.3.4. Я хочу обновить предыдущую страницу входа после нового входа, как я могу это достичь? – Taha Rushain 2 September 2017 в 14:37
  • 4
    @TahaRushain Вы не использовали бы камень session_limitable для обновления предыдущего сеанса. Можете ли вы объяснить, почему вы хотите обновить предыдущий сеанс, если вы обращаетесь к сайту из нового браузера? Для правильного ответа на ваш вопрос требуется более подробная информация. – scarver2 3 September 2017 в 19:32
  • 5
    @TahaRushain Спасибо за разъяснение. Хороший UX замечателен. Немного помогая AJAX, просто окуните конечную точку каждые минуты n . Если вы получите 200 OK, вы все равно входите в систему. Если вы получаете 301 или 302 Redirect, затем запустите сообщение или инициируйте перенаправление в старом браузере. – scarver2 4 September 2017 в 22:39
Другие вопросы по тегам:

Похожие вопросы: