【发布时间】:2020-06-29 23:04:49
【问题描述】:
TL;DR:在使用 Devise 的多租户应用程序中,用户应该能够在不同的租户/帐户上使用相同的电子邮件进行注册。如何让 Devise 使用 User.find_for_database_authentication 中的 account_id?
我有一个多租户应用程序。每个子域都属于一个帐户,有许多用户和管理员(不同的表,它们之间没有继承关系)。
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
这种工作,但我发现两个问题/缺点:
当我与用户注销时,它对管理员也是如此(对开发来说有点烦人)
我想在
User.find_for_database_authentication上使用account_id,并避免加入。 我不知道该怎么做,因为subdomain是由 Devise/Warden 自动处理的。warden_conditions键应该是email和account_id。
【问题讨论】:
-
在 ApplicationController 上设置
Thread.current[:account_id] = @account.id是一种选择,但 Devise 应该有更好的选择!
标签: ruby-on-rails devise multi-tenant