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

时间:2016-01-20 01:35:56

标签: ruby-on-rails devise warden

我的身份验证需要独立:

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

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

谢谢!

1 个答案:

答案 0 :(得分:4)

为了做到这一点,您需要将身份验证的范围缩小到仅限于子域。

以下是有关如何完成此操作的Docs页面。我将在此处添加以供参考:

<强>概述

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

    首先,您必须删除电子邮件索引唯一性约束。因为我们将把它转换为范围查询,所以我们将新索引的范围限定为子域。如果这是一个全新的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

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

    复制所需的验证

    覆盖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
    

    恭喜,用户登录现在限定为子域名!