【问题标题】:Using the same email for different accounts on a multi-tenant app with Devise使用 Devise 在多租户应用程序上为不同帐户使用相同的电子邮件
【发布时间】: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

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

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

  2. 我想在User.find_for_database_authentication 上使用account_id,并避免加入。 我不知道该怎么做,因为 subdomain 是由 Devise/Warden 自动处理的。 warden_conditions 键应该是 emailaccount_id

【问题讨论】:

  • 在 ApplicationController 上设置 Thread.current[:account_id] = @account.id 是一种选择,但 Devise 应该有更好的选择!

标签: ruby-on-rails devise multi-tenant


【解决方案1】:

据此Wiki

如果您使用子域以外的列名将登录范围限定为子域,则可能必须使用 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 以支持密码恢复

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-23
    • 2023-03-29
    • 1970-01-01
    • 2022-11-25
    • 1970-01-01
    • 2020-07-25
    • 2016-07-18
    相关资源
    最近更新 更多