如何为 Devise user_signed_in 添加额外的范围?帮手?

How do you add additional scoping to Devise user_signed_in? helper?

我的身份验证需要独立于:

subdomain1.domain.com subdomain2.domain.com 等等

现在使用设计 user_signed_in? 助手 - 如果有人在 subdomain1 上进行身份验证,它正在 subdomain2 上工作。我想添加一个 tenant_id 范围来防止这种情况发生。

我已经能够在我的模型中使用以下方法对登录身份验证执行此操作:

def self.find_for_database_authentication(warden_conditions)
      where(:email => warden_conditions[:email], :tenant_id => warden_conditions[:tenant_id]).first
end

但我不清楚如何在登录检查中执行此操作。

谢谢!

为此,您需要将身份验证范围缩小到子域。

这里是关于如何完成此操作的 Docs 页面。我会在这里添加它以供参考:

概览

  1. 修改 Devise-generated 迁移以删除电子邮件唯一性约束的索引
  2. 更改登录密钥以包括 :subdomain
  3. 覆盖 Devise 挂钩方法 find_for_authentication

修改迁移

首先,您必须删除电子邮件索引唯一性约束。因为我们会将其转换为范围查询,所以我们会将新索引的范围限定为子域。如果这是全新的 Devise 模型,您可以打开 Devise 迁移并更改以下内容:

# db/migrate/XXX_devise_create_users.rb
def change
  # Remove this line
  add_index :users, :email, :unique => true

  # Replace with
  add_index :users, [:email, :subdomain], :unique => true
end

如果这是一个现有项目,您将需要创建一个新的迁移以删除旧索引并添加一个新索引:

rails g migration reindex_users_by_email_and_subdomain


# db/migrate/XXX_reindex_users_by_email_and_subdomain.rb
def change
  remove_index :users, :email
  add_index :users, [:email, :subdomain], :unique => true
end

更改登录密钥

在您的 Devise 模型中,将 :subdomain 添加到 :request_keys。默认情况下 :request_keys 设置为 []

   # app/models/user.rb
class User
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, request_keys: [:subdomain]
end

如果您有多个 Devise 模型并且您希望所有模型都具有相同的 :request_keys 配置,您可以在 config/initializers/devise.rb

中进行全局设置
config.request_keys = [:subdomain] # default value = []

如果您还希望在没有子域的情况下仍然能够使用 URL 登录,:request_keys 也可以使用布尔值进行散列,指示是否需要密钥。

config.request_keys = { subdomain: false }

检查模型的设计调用中是否没有 :validatable

如果这样做,:validatable 将防止多个记录具有相同的电子邮件,即使在不同的子域中也是如此。如果你想保留一些验证,你可以从 https://github.com/plataformatec/devise/blob/master/lib/devise/models/validatable.rb

复制你想要的那些

Override Devise auth finder hook

对于Authenticatable,Devise使用了钩子方法Model.find_for_authentication。覆盖它以包含您的其他查询参数:

# app/models/user.rb
class User < ActiveRecord::Base
  def self.find_for_authentication(warden_conditions)
    where(:email => warden_conditions[:email], :subdomain => warden_conditions[:subdomain]).first
  end
end

恭喜,用户登录现在仅限于子域!