ruby-on-rails - 使用 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
这种作品,但我发现了两个问题/缺点:
当我与用户注销时,它对管理员也是如此(对开发来说有点烦人)
我想使用
account_id
onUser.find_for_database_authentication
并避免 JOIN。我不知道该怎么做,就像subdomain
Devise/Warden 自动处理的那样。warden_conditions
键应该是email
andaccount_id
。
解决方案
根据这个维基
如果您使用子域以外的列名将登录范围限定为子域,则可能必须使用 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 以支持密码恢复
推荐阅读
- javascript - 刷新时反应路由器空白页面。页面有道具
- javascript - 如何从 MongoDB 字符串数组中检索主题标签?
- perl - mod_perl2:按模块位置而不是名称使用模块
- java - Java - 创建抽象对象的工厂类?
- r - 使用 R 中的简单特征库识别多边形的公共边界
- vim - VIm - 查找和替换管道字符
- mongodb - 删除 MongoDB 中的记录而不是不再有有效的 URL
- vb.net - 如何使用 LinQ 更新数据表中单行中的单列
- google-sheets - Google 表格是否具有 Excel 等“易失性”功能?
- java - 无法建立 WiFi 连接 Android API29