Rails 5,Apartment and Devise:使用子域名登录无效

时间:2017-02-26 11:14:11

标签: ruby-on-rails ruby devise apartment-gem

我已经使用Apartment(1.2.0)和Devise(4.2.0)设置了Rails 5应用程序。由于某些DDNS问题,存在约束,即只能在app.myapp.com下访问该应用(请注意子域app)。 myapp.com重定向到app.myapp.com

我的使用案例是,每个注册到应用的用户(租户)都应通过其子域(例如tenant.myapp.com)访问其特定数据。不应将用户限定为其子域。基本上应该可以从任何子域登录。重定向到租户的正确子域由ApplicationController处理。根据Devise标准,登录页面位于app.myapp.com/users/sign_in。这就是问题的起点:

由于“电子邮件或密码不正确”错误,用户无法登录。

在开发过程中,我玩了一下。从lvh.me登录可以很好地运行。用户已登录并重定向到其子域。尝试使用app.lvh.me导致上述问题。

我已将会话存储设置为:

# /config/initializers/session_store.rb
Rails.application.config.session_store :cookie_store, key: '_myapp_session', domain: {
  production:   '.app.myapp.com',
  staging:      '.app.myapp.com',
  development:  '.app.lvh.me'
}.fetch(Rails.env.to_sym, :all)

我也试过了以下两种方法都不起作用:

Rails.application.config.session_store :cookie_store, key: '_myapp_session', domain: :all

我需要做什么才能从任何子域登录?

测试案例将是:

用户user1访问网址app.myapp.com/users/sign_in提供其凭据,然后登录并重定向到user1.myapp.com

奖励:user1访问网址another_user.myapp.com/users/sign_in提供其凭据,然后登录并重定向到user1.myapp.com

修改

其他相关配置:

# /config/initializers/apartment.rb
config.excluded_models = %w{ User }
config.tenant_names = lambda { User.pluck :subdomain }
config.tld_length = 2
Rails.application.config.middleware.insert_before Warden::Manager, Apartment::Elevators::FirstSubdomain
Apartment::Elevators::FirstSubdomain.excluded_subdomains = ExcludedSubdomains.subdomains

# /app/classes/excluded_subdomains.rb
class ExcludedSubdomains
  def self.subdomains
    %w( www admin test public private staging app web net )
  end # subdomains
end # class

# /app/models/user.rb
class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable,
         :confirmable, :lockable

  after_create :create_tenant
  after_destroy :delete_tenant

  # other stuff
  def create_tenant
    Apartment::Tenant.create(subdomain)
  end # create_tenant


  def delete_tenant
    Apartment::Tenant.drop(subdomain)
  end # delete_tenant
end # class

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception

  before_action :authenticate_user!
  before_action :redirect_to_subdomain

  private
  def redirect_to_subdomain
    return if self.is_a?(DeviseController) || self.is_a?(Users::OnboardingController)

    if current_user.present? && request.subdomain != current_user.subdomain
      redirect_to main_index_url(subdomain: current_user.subdomain)
    end # if
  end # redirect_to_subdomain

  def after_sign_in_path_for(resource_or_scope)
    users_onboarding_start_url(subdomain: resource_or_scope.subdomain)
  end # after_sign_in_path_for

  def after_sign_out_path_for(resource_or_scope)
    successful_logout_url(subdomain: '')
  end # after_sign_out_path_for
end # class

2 个答案:

答案 0 :(得分:9)

我发现了问题!不使用.app预先添加应用域,域应该没有前置子域,而是一个点。像这样:

# /config/initializers/session_store.rb
Rails.application.config.session_store :cookie_store, key: '_myapp_session', domain: {
  production:   '.myapp.com',
  staging:      '.myapp.com',
  development:  '.lvh.me'
}.fetch(Rails.env.to_sym, :all)

我很难找到这个简单的错误,甚至我创建了一个示例应用程序。由于这个例子已经存在,我想我可以分享它。它可以在GitHub找到。

答案 1 :(得分:1)

可以将apartment配置为从多租户中排除某些模型。

config.excluded_models = ["User"]

上述指令允许您在所有租户中维护一个普通用户。

如何将此用户定位到特定租户并将其重定向到正确的子域需要在设计模型和控制器前面进行一些重新设计。您可以考虑在subdomain模型中添加其他列,例如tenant_nameUser,以便与特定客户端关联,并扩充/扩展devise控制器以注册,登录和重定向用户正确。

请使用您的域名替换.testdomain.com,而不是在session_store.rb中添加当前条目,尝试在session_store.rb中添加以下行。

Rails.application.config.session_store :cookie_store, key: '_jcrop_app_session', domain: ".testdomain.com"

虽然我使用myapp1app等任何子域成功登录购买,但我没有尝试代码的重定向部分。