首页 > 解决方案 > 使用 Devise 在多租户应用程序上为不同帐户使用相同的电子邮件

问题描述

TL;DR:在带有 Devise 的多租户应用程序中,用户应该能够在不同的租户/帐户上使用相同的电子邮件进行注册。我怎样才能让设计使用 account_id User.find_for_database_authentication


我有一个多租户应用程序。每个子域都属于一个帐户,有许多用户和管理员(不同的表,它们之间没有继承)。

class User < ApplicationRecord
  belongs_to :account
  devise :database_authenticatable, :confirmable, :recoverable, :rememberable
  validates :email, uniqueness: true
end

class AdminUser < ApplicationRecord
  belongs_to :account
  devise :database_authenticatable, :confirmable, :recoverable, :rememberable
end

# config/routes.rb
scope module: 'auth' do
  devise_for :users, path: ''
  devise_for :admins, path: 'admin', class_name: 'AdminUser', ...
end

# /sign_in for users, /admin/sign_in for admins
# (you can log as both at the same time)

认为效果很好,但我需要允许用户在不同的租户/帐户上使用相同的电子邮件登录。首先,我修复了验证:

class User < ApplicationRecord
  validates :email, uniqueness: { scope: :account_id }
end

问题是,当用户注册/登录时,Devise 将搜索第一个带有一些电子邮件的用户,而不管account_id,所以如果我在 subdomain1 和 subdomain2 上共享相同的电子邮件地址,当我登录到 subdomain2 时,我得到来自 subdomain1 的用户信息(这是错误的)

设计文档建议配置request_keys和重新定义User.find_for_database_authentication

  # config/initializers/devise.rb
  config.request_keys = [:subdomain]

  # app/models/user.rb
  def self.find_for_database_authentication warden_conditions
    joins(:account).where(
      email: warden_conditions[:email],
      accounts: {subdomain: warden_conditions[:subdomain]}
    ).first
  end

这种作品,但我发现了两个问题/缺点:

  1. 当我与用户注销时,它对管理员也是如此(对开发来说有点烦人)

  2. 我想使用account_idonUser.find_for_database_authentication并避免 JOIN。我不知道该怎么做,就像subdomainDevise/Warden 自动处理的那样。warden_conditions键应该是emailand account_id

标签: ruby-on-railsdevisemulti-tenant

解决方案


根据这个维基

如果您使用子域以外的列名将登录范围限定为子域,则可能必须使用 authentication_keys。例如,如果您有 subdomains 表并且在您的设计模型上使用 subdomain_id 来限定用户,您将必须添加 authentication_keys: [:email, :subdomain_id]

所以我认为你应该

devise :database_authenticatable, :confirmable, :recoverable, :rememberable, authentication_keys[:account_id]

另外,我认为您应该重新定义 find_first_by_auth_conditions 而不是 find_for_database_authentication 以支持密码恢复


推荐阅读