设计 - bypass_sign_in 没有 active_for_authentication?打回来

Devise - bypass_sign_in without active_for_authentication? callback

我在我的应用程序中有非活动帐户的功能来处理这个我重写 active_for_authentication? 方法如下

def active_for_authentication?
  super && activated?
end

但是在我的应用中super admin也可以直接登录其他用户帐号,不管是不是active

bypass_sign_in(User.find(resource.id))

我用上面的方法绕过登录,它允许我只为激活用户直接登录,当我为非激活用户登录时,它进入无限循环。

有解决这个问题的方法吗?运行 active_for_authentication? bypass_sign_in 时不回调?

当管理员登录到另一个用户帐户时,您可以在会话中存储一些额外的数据,这清楚地表明这是 super admin 模式。

def login_as(another_user)
  return unless current_user.super_admin?

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

遗憾的是,您无法在 Rails 模型中访问 session,但您可以将所需的会话信息存储在模型中可用的某些按请求全局变量中。解决方案可能是这样的:

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

在应用程序控制器中:

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

此外,您应该确保在超级用户注销时从 session 中删除 :super_admin_mode 标志。也许它会自动发生,我不确定。也许您需要手动覆盖 Devise::SessionsController#destroy 方法(参见下面的示例)

  def destroy
    session[:super_admin_mode] = nil
    super
  end

另请阅读本文以更好地了解 devise 如何处理会话 Stop Devise from clearing session

我最近遇到了一个类似的问题,我需要允许管理员以在 Devise 中不活跃的普通用户身份登录。我想出了以下不涉及使用 Thread.current 的解决方案(在进一步在线调查后,似乎使用 Thread.current 可能是解决此问题的不稳定方法)。

您可以创建一个名为 ProxyUser 的 User 子类,它具有 active_for_authentication? return 是的。像这样:

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 身份登录您的应用时将 return current_user 为零。您的应用程序将有一个名为 current_proxy_user 的对象,它将成为您登录的 ProxyUser 对象。在这种情况下,有很多方法可以处理由 current_user return ing nil 导致的问题(包括在应用程序控制器中覆盖 current_user)。