Devise - bypass_sign_in без active_for_authentication? Перезвони

У меня есть функциональность неактивной учетной записи в моем приложении для обработки этого метода, который я переопределяю active_for_authentication?, как показано ниже.

def active_for_authentication?
  super && activated?
end

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

bypass_sign_in(User.find(resource.id))

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

Какие-нибудь решения для решения этой проблемы или не запускать обратный вызов active_for_authentication? при bypass_sign_in?


person Vishal    schedule 18.05.2018    source источник


Ответы (2)


Когда администратор входит в другую учетную запись пользователя, вы можете сохранить некоторые дополнительные данные в сеансе, что дает понять, что это режим super admin.

def login_as(another_user)
  return unless current_user.super_admin?

  session[:super_admin_mode] = true
  bypass_sign_in(another_user)
end

К сожалению, вы не можете получить доступ к session в моделях Rails, но вы можете хранить необходимую информацию о сеансе в некоторой глобальной переменной для каждого запроса, которая доступна в моделях. Решение может быть таким:

module SessionInfo
  def self.super_user_mode?
    !!Thread.current[:super_user_mode]
  end

  def self.super_user_mode=(value)
    Thread.current[:super_user_mode] = value
  end
end

В ApplicationController:

class ApplicationController < ActionController::Base
  before_filter :store_session_info

  private

  def store_session_info
    SessionInfo.super_user_mode = session[:super_admin_mode]
  end
end

В модели:

def active_for_authentication?
  super && (activated? || SessionInfo.super_user_mode?)
end

Кроме того, вы должны убедиться, что флаг :super_admin_mode снят с session, когда суперпользователь выходит из системы. Может быть, это происходит автоматически, я не уверен. Возможно, вам нужно будет сделать это вручную, переопределив метод Devise::SessionsController#destroy (см. пример ниже)

  def destroy
    session[:super_admin_mode] = nil
    super
  end

Также прочитайте это, чтобы лучше понять, как devise обрабатывает сеанс Остановить Devise от сеанса очистки

person chumakoff    schedule 18.05.2018
comment
Мы не можем использовать сеанс в модели - person Vishal; 18.05.2018
comment
Правильно) Отредактировал ответ - person chumakoff; 18.05.2018
comment
Большое спасибо, я уже сделал это до ответа, но спасибо за ваш ответ, я проголосую и приму его. еще одна вещь, во-первых, нам не нужно переопределять метод уничтожения контроллера сеансов, а во-вторых, нам нужно включить модуль SessionInfo в модель, поэтому мы напрямую обращаемся к методу super_user_mode?. не могли бы вы обновить свой ответ с этим изменением? и если вопрос хорош, вы также можете проголосовать за мой вопрос;) - person Vishal; 18.05.2018
comment
1) Не имеет смысла включать SessionInfo в модель User. 2) В вашем случае не нужно переопределять метод destroy, но, возможно, это кому-то понадобится, поэтому я не буду это менять. - person chumakoff; 18.05.2018

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

Вы можете создать подкласс User с именем ProxyUser, у которого есть атрибут active_for_authentication? вернуть истину. Что-то вроде этого:

class ProxyUser < User
  # If you have a type column on User then uncomment this line below
  # as you dont want to expect ProxyUser to have type 'ProxyUser'
  #
  # self.inheritance_column = :_type_disabled
  
  devise :database_authenticatable
  
   def active_for_authentication?
    true
  end
 end

Затем в контроллере вы хотите что-то вроде этого:

proxy_user = ProxyUser.find(params[:user_id])

sign_in :proxy_user, proxy_user

Также в ваших маршрутах вам нужно будет разработать ProxyUser, поэтому включите:

  devise_for :proxy_users

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

sign_out :proxy_user

И, наконец, обратите внимание, что в вашем приложении вы можете ожидать current_user в разных местах (например, если вы используете CanCanCan для авторизации), и теперь, когда вы входите в систему как proxy_user, ваше приложение возвращает current_user как nil. Вместо этого ваше приложение будет иметь объект с именем current_proxy_user, который будет вашим зарегистрированным объектом ProxyUser. Существует много способов справиться с проблемами, возникающими в результате того, что ваш current_user возвращает nil в этом случае (включая перезапись current_user в вашем контроллере приложения).

person armont_development    schedule 22.04.2021
comment
Кажется более сложным способом - person Vishal; 23.04.2021