在Rails 3中跨子域共享登录会话的正确方法?

ape*_*ure 7 authentication ruby-on-rails-3

我在互联网上发现的关于此的所有信息都说使用类似的东西

Login::Application.config.session_store :cookie_store, :key => '_login_session', :domain => '.domain.com'

并对我要共享该会话的所有子域使用相同的密钥.当我这样做时,子域之间不会传递身份验证.实际上,当我访问任何所谓的共享会话时,初始会话将被覆盖

即在login.domain.com上,我运行身份验证,返回用户名和会话user_id.然后我去sub.domain.com,它应该返回与login.domain.com相同的信息,但不会.在此之后,我回到login.domain.com,我也不再在那里进行身份验证.

在sub.domain.com上,session_store.rb文件如下所示:

Something::Application.config.session_store :cookie_store, :key => '_login_session', :domain => '.domain.com'

我用过:所有的:域值,也有相同的结果.如果我删除上面的:域设置,那么初始会话不会被覆盖,但它也不会被共享.

当我在Firefox Cookie的Cookie编辑器中查看Cookie时,两个子域名都使用相同的Cookie名称,但不会共享身份验证.这是一个非常基本的Users表,我使用OpenID和OAuth来执行Omniauth的身份验证

kar*_*dog 6

更新:建议的解决方案毕竟不是那么难看,广告交易平台和DSP/SSP使用相同的技术来交换访问者的会话ID,以便他们可以更好地使用广告定位访问者(下次访问者再次在其网络中弹出时) )


如果您可以绕过浏览器跨域屏障,则可以执行此操作.例如,JSONP专门为此目的而构建.是的,会话信息总是集中存储,否则如果您收到会话ID为"zigzag"的请求,您如何检查它是否有效?

在login.domain.com上进行身份验证的"那些"站点可能使用ajax代理,或使用其他方法来解决跨域问题.

最古老的"技巧"是在应用程序中创建一个看起来像图像的钩子,因为图像可以从任何地方加载.

例如,在login.domain.com上,您对用户进行身份验证,发送到服务器并返回响应,并且cookie将存储在login.domain.com下,带有会话ID(也存储在服务器中) .然后 - 从Javascript - 你得到一个附有会话ID的图像,如http://any.domain.com/path/image.jpg?sessionID=abcd - >在响应中发回的任何cookie都将存储在任何.domain.com

另一个解决方案- 与之前一样丑陋 -是使用隐藏的iframe来调用any.domain.com(当成功进行身份验证时),该请求将返回响应,并且其cookie将在any下写入. domain.com域名.

如果您有多个子域,并且可能会使您的架构复杂化,我强烈建议您创建一个代理,并使其可用于同一IP地址上的每个子域.然后,无论用户进入何处,对于每个子域,身份验证过程将始终相同.


Eva*_*van 6

由于某种原因,为域添加点前缀不起作用(rails 3.2.11).它花了一块自定义中间件来修复它.该解决方案的摘要如下.

tl; dr:你需要编写一个自定义的Rack Middleware.你需要将它添加到你的conifg/environments/[production|development].rb.这是在Rails 3.2.11上

Cookie会话通常仅存储在您的顶级域中.

如果你查看Chrome -> Settings -> Show advanced settings… -> Privacy/Content settings… -> All cookies and site data… -> Search {yourdomain.com}你可以看到sub1.yourdomain.comothersub.yourdomain.com和将有单独的条目yourdomain.com

挑战是在所有子域中使用相同的会话存储文件.

第1步:添加自定义中间件类

这就是Rack Middleware的用武之地.一些相关的机架和轨道资源:

这是一个你应该添加的自定义类.lib 这是由@Nader编写的,你们都应该感谢他

# Custom Domain Cookie
#
# Set the cookie domain to the custom domain if it's present
class CustomDomainCookie
  def initialize(app, default_domain)
    @app = app
    @default_domain = default_domain
  end

  def call(env)
    host = env["HTTP_HOST"].split(':').first
    env["rack.session.options"][:domain] = custom_domain?(host) ? ".#{host}" : "#{@default_domain}"
    @app.call(env)
  end

  def custom_domain?(host)
    host !~ /#{@default_domain.sub(/^\./, '')}/i
  end
end
Run Code Online (Sandbox Code Playgroud)

基本上它的作用是将所有cookie会话数据映射回与您的根域相同的完全相同的cookie文件.

第2步:添加到Rails配置

既然您在lib中有自定义类,请确保自动加载它.如果这对您没有任何意义,请看这里:Rails 3自动加载

首先要确保您使用cookie商店在系统范围内.在config/application.rb我们告诉Rails使用cookie商店.

# We use a cookie_store for session data
config.session_store :cookie_store,
                     :key => '_yourappsession',
                     :domain => :all
Run Code Online (Sandbox Code Playgroud)

这里提到的原因是因为这:domain => :all条线.还有其他人建议指定:domain => ".yourdomain.com"而不是:domain => :all.出于某种原因,这对我不起作用,我需要如上所述的自定义中间件类.

然后在你的config/environments/production.rb添加中:

config.middleware.use "CustomDomainCookie", ".yourdomain.com"
Run Code Online (Sandbox Code Playgroud)

请注意,前面的点是必要的.有关原因,请参阅" 在父域请求中发送的子域cookie? ".

然后在你的config/environments/development.rb添加中:

config.middleware.use "CustomDomainCookie", ".lvh.me"
Run Code Online (Sandbox Code Playgroud)

lvh.me技巧映射到localhost.这很棒.有关详细信息,请参阅此有关子域的Railscast此注释.

希望应该这样做.老实说,我不完全确定为什么这个过程很复杂,因为我觉得跨域子站点很常见.如果有人对这些步骤背后的原因有任何进一步的见解,请在评论中启发我们.