Ruby on Rails 如何同时处理域名级别与子域名级别会话Cookie?
前置准备
所有子应用共享主域名会话的加密密钥(该要求是加密Cookie跨应用读取的底层逻辑决定,无法绕过),子应用私有会话可继续使用各自独立的secret_key_base,互不影响。统一密钥建议存储在各应用的环境变量中,不要硬编码到代码库。
实现步骤
1. 自定义主域名会话中间件
新建 config/initializers/domain_session.rb 初始化文件,复用Rails原生CookieStore能力实现主域名会话,同时暴露全局访问方法:
# 主域名会话存储类,继承Rails原生CookieStore class DomainSessionStore < ActionDispatch::Session::CookieStore def initialize(app, options = {}) options[:domain] = :all # 自动适配当前环境的顶级主域名,也可硬写为 "mydomain.com" options[:key] = "_domain_shared_session" options[:secret_key_base] = ENV["DOMAIN_SESSION_SECRET"] # 所有子应用统一的加密密钥 options[:httponly] = true options[:same_site] = :lax super end end # 给控制器、视图暴露domain_session调用方法 module DomainSessionAccessor extend ActiveSupport::Concern included { helper_method :domain_session } def domain_session request.env["rack.session.domain_shared"] end end ActionController::Base.include DomainSessionAccessor
2. 挂载中间件
在 config/application.rb 中把自定义的主域名会话中间件挂载到默认会话中间件之后,避免冲突:
config.middleware.insert_after( ActionDispatch::Session::CookieStore, DomainSessionStore, key: "_domain_shared_session", env_key: "rack.session.domain_shared" )
3. 配置子应用私有会话
各子应用保持默认会话配置,指定独立的Cookie名和子域名即可,和主域名会话完全隔离:
# config/initializers/session_store.rb Rails.application.config.session_store :cookie_store, key: "_app1_private_session", domain: "app1.mydomain.com" # 仅当前子域名可访问
使用方式
调用逻辑和Rails原生session完全一致:
- 子应用私有会话读写:
session[:app_local_config] = "xxx",仅当前子域名应用可访问 - 跨子域共享会话读写:
domain_session[:sso_user_id] = 123,所有mydomain.com下的子应用都可访问 - 统一退出登录:同时调用
reset_session(清空私有会话)和domain_session.clear(清空共享会话)即可
方案优势
- 完全复用Rails原生会话的加密、序列化、过期、安全校验逻辑,无需手动实现Cookie处理,避免安全漏洞
- 两套会话完全隔离,子应用私有会话不需要共享密钥,不会泄露各应用的私有数据
- 调用方式和原生API对齐,无额外学习成本,符合Rails开发习惯
内容的提问来源于stack exchange,提问作者chech
相关产品推荐
相关产品推荐

