【问题标题】:Why isn't "expiry" header updated with each new request to Ruby on Rails app?为什么每次对 Ruby on Rails 应用程序的新请求都不会更新“过期”标头?
【发布时间】:2019-04-15 16:16:24
【问题描述】:

我正在使用 Devise :timeoutable 模块使会话在一段时间不活动后过期。每个新请求都会重置超时,因此会话到期日期会发生变化。但它只是没有反映在响应客户端发送的expiry 标头中。

我注意到expiry 响应标头对于我发送到服务器的所有 XHR 都是不变的。即使刷新页面后,expiry 标头也不会更新。换句话说,标头的值仅对我登录后发送的第一个请求是正确的,然后它保持不变。

由于 Devise 将 auth 标头附加到开箱即用的每个响应中,因此无需演示相关代码。

响应标题如下所示:

access-token: qK5XalnvENIXJDHGCKJ5_A
Cache-Control: no-cache
client: c-4_msWmyUFD7PwD7fPW5Q
Connection: keep-alive
Content-Encoding: gzip
Content-Type: application/json; charset=utf-8
Date: Mon, 15 Apr 2019 15:52:32 GMT
expiry: 1556548396
Server: nginx
token-type: Bearer
Transfer-Encoding: chunked
uid: user@email.com
Vary: Origin
X-Request-Id: 2fa70ebf-dcf2-4680-8c25-68d7b5e12b1b
X-Runtime: 0.021004

以及请求标头(如果相关):

GET /api/user/context HTTP/1.1
Host: qa.whiz.ai:9060
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
access-token: qK5XalnvENIXJDHGCKJ5_A
client: c-4_msWmyUFD7PwD7fPW5Q
Accept: application/json, text/plain, */*
expiry: 1556548396
uid: user@email.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36
token-type: Bearer
Referer: https://my-page.example.com/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9,uk-UA;q=0.8,uk;q=0.7,ru-UA;q=0.6,ru;q=0.5
Cookie: ...

我尝试从请求标头中删除expiry,但没有效果。

这是预期的行为吗?设计不应该开箱即用地在该标头中发送实际值吗?

我想知道能够在客户端上执行某些操作的实际到期时间。为此,我可以尝试描述here 的解决方案,但如果我可以利用每个响应中已经存在的标头,则会简单得多。

【问题讨论】:

  • 好吧,到期标头不用于身份验证。相反,它是一种缓存控制机制,以便客户端可以缓存请求而不会过时。
  • 这与设计令牌身份验证有关,不是吗?这是相关来源:github.com/lynndylanhurley/devise_token_auth/blob/master/app/… 但是我完全误解了该标题的目的

标签: ruby-on-rails ruby session devise


【解决方案1】:

Devises Timeoutable 模块与过期标头完全无关。仅仅因为两个概念看起来相似并不意味着它们是相关的。

Timeoutable 将last_request_at 存储在会话中(默认为 cookie 存储)。

您可以通过以下方式获取值:

ENV['warden'].session(scope)['last_request_at']

scope 是基于您的模型的名称。

来自the source

Warden::Manager.after_set_user do |record, warden, options|
  scope = options[:scope]
  env   = warden.request.env

  if record && record.respond_to?(:timedout?) && warden.authenticated?(scope) &&
     options[:store] != false && !env['devise.skip_timeoutable']
    last_request_at = warden.session(scope)['last_request_at']

    if last_request_at.is_a? Integer
      last_request_at = Time.at(last_request_at).utc
    elsif last_request_at.is_a? String
      last_request_at = Time.parse(last_request_at)
    end

    proxy = Devise::Hooks::Proxy.new(warden)

    if record.timedout?(last_request_at) &&
        !env['devise.skip_timeout'] &&
        !proxy.remember_me_is_active?(record)
      Devise.sign_out_all_scopes ? proxy.sign_out : proxy.sign_out(scope)
      throw :warden, scope: scope, message: :timeout
    end

    unless env['devise.skip_trackable']
      warden.session(scope)['last_request_at'] = Time.now.utc.to_i
    end
  end
end

过期标头用于控制每个单独响应的缓存。客户端应该如何以及何时考虑指定响应陈旧的启发式方法非常复杂,但过期标头包含响应应该何时过期的时间戳。

【讨论】:

  • 谢谢,我认为它与超时有关,但我发现它有所不同(在此处找到源:github.com/lynndylanhurley/devise_token_auth/blob/master/app/…
  • 是的,它更像是 HTTP 缓存工作原理的基本原则。当然,设计令牌身份验证可能会使用到期标头,但与螺丝钉与火箭的关系并不比它更紧密。
  • 但是无论如何,如果它没有针对较新的响应进行更新,那么它对确定响应何时过期有何用处?例如。现在是 9:00pm,我的 expiry 标头可能包含过时的时间戳,例如 8:55pm - 这是预期的行为还是配置错误?
  • 问题是该响应有Cache-Control: no-cache,这意味着无论如何都不会使用过期标头。
  • Heroku 有一篇关于 HTTP 缓存如何工作的相当不错的文章。 devcenter.heroku.com/articles/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-09
  • 1970-01-01
  • 1970-01-01
  • 2017-04-17
  • 2012-03-03
  • 1970-01-01
相关资源
最近更新 更多