添加 'SameSite=None;' 通过 Rack 中间件到 Rails 的 cookie?

Kel*_*nan 8 cookies rack middleware ruby-on-rails samesite

2020 年 2 月 4 日,Google Chrome 将需要SameSite=None;添加到所有跨站点 cookie。 Rails 6.1 和很快的 Rails 6.0same_site: :none为 rails cookie 哈希添加了一个选项:

cookies["foo"]= {
  value: "bar",
  expires: 1.year.from_now,
  same_site: :none
} 
Run Code Online (Sandbox Code Playgroud)

但是较旧的 Rails 5.x 应用程序将无法获得升级以访问same_site选项哈希。我知道SameSite=None;可以使用以下方法将cookie 选项手动添加到控制器中的 Rails:

response.headers["Set-Cookie"] = "my=cookie; path=/; expires=#{1.year.from_now}; SameSite=None;"
Run Code Online (Sandbox Code Playgroud)

但是我的 Rails 5.x 应用程序使用了复杂的 cookie 对象来修改 cookie。我不想将它们分开,而是想编写 Rack 中间件来一次手动更新具有该SameSite=None;属性的所有 cookie 。

这个 StackOverflow 答案显示了一种可以修改 cookie 以更新机架中间件中的 cookie 的方法:

# lib/same_site_cookie_middleware
class SameSiteCookieMiddleware
  def initialize(app)
    @app = app
  end

  def call(env)
    status, headers, body = @app.call(env)
    # confusingly, response takes its args in a different order
    # than rack requires them to be passed on
    # I know it's because most likely you'll modify the body, 
    # and the defaults are fine for the others. But, it still bothers me.

    response = Rack::Response.new body, status, headers

    response.set_cookie("foo", {:value => "bar", :path => "/", :expires => 1.year.from_now, same_site: :none})
    response.finish # finish writes out the response in the expected format.
  end
end
Run Code Online (Sandbox Code Playgroud)
# application.rb
require 'same_site_cookie_middleware'
config.middleware.insert_after(ActionDispatch::Cookies, SameSiteCookieMiddleware)
Run Code Online (Sandbox Code Playgroud)

如何重新编写此机架中间件代码以手动附加SameSite=None;到每个现有 cookie 中?

Car*_*nke 4

我能够让它与以下内容一起工作:

# frozen_string_literals: true

class SameSiteCookies

  def initialize(app)
    @app = app
  end

  def call(env)
    status, headers, body = @app.call(env)

    set_cookie_header = headers['Set-Cookie']

    if set_cookie_header && !(set_cookie_header =~ /SameSite\=/)

      headers['Set-Cookie'] << ';' if !(set_cookie_header =~ /;$/)
      headers['Set-Cookie'] << ' SameSite=None'
      headers['Set-Cookie'] << '; Secure' if env['rack.url_scheme'] == 'https';

    end

    [status, headers, body]
  end
end
Run Code Online (Sandbox Code Playgroud)

并添加到中间件:

Rails.application.config.middleware.insert_before(ActionDispatch::Cookies, SameSiteCookies)
Run Code Online (Sandbox Code Playgroud)