Rails 仅在 2 个子域之间共享 cookie,并对所有其他子域使用单独的 cookie

问题描述 投票:0回答:1

我有一个使用 Devise 进行身份验证的 Rails 7 SaSS 应用程序,该应用程序在

www.my-site.com
子域上注册新用户,并在
dashboard.my-site.com
注册后将其重定向到实际应用程序。

我可以使用以下 session_store.rb 代码轻松完成此任务:

Rails.application.config.session_store :cookie_store, key: "_myapp_session", domain: ["dashboard.my-site.com", "www.my-site.com"], tld_length: 2

但问题是我的应用程序允许用户拥有自定义子域 - 应该有完全独立的 cookie - 例如,

a-customer-subdomain.my-site.com

所以我的想法是,我实际上需要提前动态设置 :cookie_store - 就像在中间件中一样 - 因此我们对

www
dashboard
子域使用一种设置,对任何其他子域或域使用完全不同的设置。但这就是我发现自己陷入困境的地方。我该如何进行这些调整?

ruby-on-rails cookies devise ruby-on-rails-7
1个回答
1
投票

看看“Rails 3

session_store domain :all
真正做了什么?”,还有Prathamesh Sonpatki的“使用多个子域构建Rails应用程序”(2020年3月),您确实应该使用中间件来动态设置基于传入请求的 cookie 域。

# lib/middleware/dynamic_cookie_domain.rb
class DynamicCookieDomain
  def initialize(app)
    @app = app
  end

  def call(env)
    host = env["HTTP_HOST"].split(':').first
    Rails.application.config.session_store :cookie_store, key: "_myapp_session", domain: custom_domain(host), tld_length: 2
    @app.call(env)
  end

  private

  def custom_domain(host)
    case host
    when 'www.my-site.com', 'dashboard.my-site.com'
      ['dashboard.my-site.com', 'www.my-site.com']
    else
      host
    end
  end
end

如果请求来自这些主机中的任何一个,则此中间件会将会话 cookie 域设置为

['dashboard.my-site.com', 'www.my-site.com']
。对于任何其他主机,它将把会话 cookie 域设置为请求的主机。

您需要将此中间件添加到您的中间件堆栈中。您可以在应用程序配置中执行此操作:

# config/application.rb
require_relative '../lib/middleware/dynamic_cookie_domain'

module YourApp
  class Application < Rails::Application
    # ...
    config.middleware.use DynamicCookieDomain
    # ...
  end
end

这会将

DynamicCookieDomain
中间件插入到您的中间件堆栈中,确保它针对每个请求运行。

这应该满足

www
dashboard
子域与任何其他子域具有不同 cookie 设置的要求。

中间件中的

custom_domain
方法检查传入请求的主机。

  • 如果主机是

    www.my-site.com
    dashboard.my-site.com
    ,它将 cookie 域设置为
    ['dashboard.my-site.com', 'www.my-site.com']
    。这意味着会话 cookie 将在这两个子域之间共享。

  • 对于任何其他主机(可能是任何其他子域或域),它将 cookie 域设置为请求的主机。这意味着会话 cookie 将特定于该子域或域,并且不会与

    www.my-site.com
    dashboard.my-site.com
    共享。

这种基于传入请求的 Cookie 域动态设置应该允许您对

www
dashboard
子域进行一种设置,并对任何其他子域或域进行不同的设置。


这与 this answer 略有不同,如果请求来自子域,则将 cookie 域设置为二级域(例如

my-site.com
),否则设置为
:all
。这将在
my-site.com
的所有子域之间共享 cookie。

相比之下,如果请求来自这些主机中的任何一个,则 cookie 域设置为

['dashboard.my-site.com', 'www.my-site.com']
,否则设置为请求的主机。这会在
dashboard.my-site.com
www.my-site.com
之间共享 Cookie,但对所有其他子域使用单独的 Cookie。


我一直无法弄清楚如何动态更改 session_storage 键

尝试动态更改中间件内的会话存储配置似乎无效,可能是因为会话存储配置是在 Rails 应用程序启动时初始化的,而中间件内的后续修改没有产生预期的影响。

解决此挑战的一个潜在解决方案可能是在中间件内直接操作

ActionDispatch::Request
对象的会话选项,而不是尝试重新配置会话存储。

尝试修改

DynamicCookieDomain
中间件来更改
ActionDispatch::Request
对象的会话选项:

# lib/middleware/dynamic_cookie_domain.rb
class DynamicCookieDomain
  def initialize(app)
    @app = app
  end

  def call(env)
    request = ActionDispatch::Request.new(env)
    host = request.host

    domain = custom_domain(host)
    request.session_options[:domain] = domain

    @app.call(request.env)
  end

  private

  def custom_domain(host)
    case host
    when 'www.my-site.com', 'dashboard.my-site.com'
      '.my-site.com'
    else
      host
    end
  end
end

确保中间件已加载并在您的应用程序中使用:

# config/application.rb
require_relative '../lib/middleware/dynamic_cookie_domain'

module YourApp
  class Application < Rails::Application
    # ...
    config.middleware.use DynamicCookieDomain
    # ...
  end
end

使用

DynamicCookieDomain
中间件,
call
方法从
ActionDispatch::Request
哈希创建
env
对象,然后修改
session_options
对象的
Request
以设置所需的域。然后,中间件使用
env
对象中更新的
Request
哈希值调用中间件堆栈中的下一项。

这应该根据每个请求更改会话选项,而不是全局重新配置会话存储。

© www.soinside.com 2019 - 2024. All rights reserved.