【问题标题】:Why does devise redirect to current path when session times out为什么会话超时时设计重定向到当前路径
【发布时间】:2018-05-19 18:27:13
【问题描述】:

这里的代码显示,当会话超时时,devise 将重定向到当前请求的路径(由timeoutable 模块检查并强制执行):https://github.com/plataformatec/devise/blob/master/lib/devise/failure_app.rb#L120

attempted_path 在调用失败应用之前由warden 设置。

问题是:为什么要设计重定向回当前请求的路径本身?如果会话超时,那么客户端是否应该被重定向到当前实体的登录页面(UserAdmin 或其他)?

如果未设置attempted_path,它确实使用scope_url。但我不明白为什么要再次重定向到当前请求的路径?这不会导致重定向循环吗?

这个重定向循环实际上发生在 Rails 管理员身上。如果我在 Rails 管理员中为我正在验证的模型启用timeoutable,那么在会话超时后,任何请求都会导致重定向循环。

那么有人可以向我解释为什么要重定向到attempted_path 吗?坐席服务于什么用例?

其他信息 这是我想到的两个流程。

应该如何

  • 用户尝试访问页面 x。会话超时。
  • 用户被重定向到登录页面
  • 用户登录
  • 用户被重定向回页面 x

目前情况如何

  • 用户尝试访问页面 x。会话超时。
  • 用户被重定向到第 x 页。

它会重复循环,直到浏览器显示“网站未正确重定向”。

【问题讨论】:

  • 其设置为将每个用户重定向到登录/注册页面。循环是这样的:检查warden是否用户会话太长,如果是,则销毁它,重定向到尝试的页面,如果用户在没有登录的情况下无法访问它,则重定向到登录页面。最后一次重定向是因为 authenticate_user! 而发生的,它应该始终在所有需要身份验证的站点上实现,否则您将得到您与管理员描述的循环。如果没有重定向到尝试的路径,设计将不知道如何重定向到登录页面。
  • @Prometheus 谢谢。我也发现了问题并解决了。将我的发现放在下面的答案中。一个问题仍然存在:为什么设计在超时的情况下无法知道登录页面 url?为什么需要额外重定向到attempted_path?这不再是一个障碍,但肯定会非常有助于理解。

标签: ruby-on-rails devise


【解决方案1】:

经过漫长的“调试周末”后,我发现问题是因为 Session 和 Cookie 中间件放在了 Warden 之后的机架堆栈中。

我的应用程序是 Rails 5 API 应用程序,这意味着默认情况下 cookie 和会话不可用。尽管是一个 API 应用程序,但出于某些原因,我不得不合并基于会话/cookie 的身份验证机制。所以我手动将这两个中间件添加到机架堆栈中。

自从我在config/application.rb 中添加它们以来,它们几乎被添加到堆栈的远端,即在Warden 中间件本身之后。然而,Warden 中间件非常清楚地表明它需要一个 Session 和 Cookie 管理器 before 在堆栈中。这样,它所做的任何会话更改都会最终被序列化到会话和 cookie 中。

这导致失败的应用程序所做的会话更改被丢弃。因此,会话从未被清除并导致重定向循环。下面的步骤会更清楚。

应该是怎样的

  1. 用户登录。使用用户 ID 设置会话。
  2. 用户使用。使用用户 ID 更新会话。
  3. 用户空闲(至少在超时期间)
  4. 用户提出请求。请求通过同一个会话发送。
  5. 会话被识别为超时。清除会话并重定向回同一页面。
  6. 浏览器再次访问同一页面。
  7. 会话中没有用户。重定向到登录页面。

我的情况是如何发生的

  1. 用户登录。使用用户 ID 设置会话。
  2. 用户使用。使用用户 ID 更新会话。
  3. 用户空闲(至少在超时期间)
  4. 用户提出请求。请求通过同一个会话发送。
  5. 会话被识别为超时。
  6. 会话已清除,但清除的会话永远不会序列化回 cookie。 (发生这种情况是因为在身份验证失败的情况下,控制直接返回到 Warden 中间件,绕过了它通过的所有中间中间件。因此它错过了 cookie 和会话中间件)
  7. 重定向回同一页面。浏览器保持会话 cookie 不变。
  8. 浏览器使用相同的会话 cookie 再次访问相同的页面

重复步骤 5-8,直到浏览器停止并出现错误。

这是我为任何对细节感兴趣的人制作的捕获整个流程的序列图。

@Prometheous:感谢您的评论。但是我还不清楚一件事:

如果超时,如果FailureApp直接重定向到scope login url会有什么问题。你说:

如果没有重定向到尝试的路径,设计就不会知道 如何重定向到登录页面。

但是,它不能从else 部分中使用的scope_url 方法获得它吗:https://github.com/plataformatec/devise/blob/master/lib/devise/failure_app.rb#L128

scope 肯定是众所周知的。

我错过了什么?

【讨论】:

    【解决方案2】:

    我的猜测是会话超时并要求用户再次登录。

    用户尝试访问页面 x。

    结果是用户会话超时。

    用户再次登录。

    用户返回第 x 页。

    超时登录会话消息显示在请求的操作中。

    【讨论】:

    • 要遵循您描述的流程,第一个重定向必须是登录页面。只有这样,用户才能登录。 - 用户尝试访问页面 x。会话超时。 - 用户被重定向到登录页面 - 用户登录 - 用户被重定向回页面 x 现在,当前代码将执行此操作: - 用户尝试访问页面 x。会话超时。 - 用户被重定向到第 x 页。它会重复循环,直到浏览器显示“网站未正确重定向”。
    【解决方案3】:

    很高兴我能以某种方式帮助你!您在分析整个设计循环过程方面做得非常出色!

    但是,我认为您正在处理一个非常深的嵌套错误,或者设计的设置不正确。我自己在一个更大的项目上对其进行了测试,效果很好。

    在 Devise.rb 中我没有注释:

    config.timeout_in = 10.seconds
    

    并出于测试目的将超时更改为 10 秒。

    我有一个关于这个项目的常见问题页面,其中有一个 page_controller。我在 page_controller 里面添加了:

    before_action :authenticate_user!
    

    在我的设计模型中,在本例中是用户,我添加了:

      devise :database_authenticatable, :registerable,
             :recoverable, :rememberable, :trackable, :validatable,
             :omniauthable, :timeoutable
    

    当我登录用户时,转到常见问题页面,等待 10 秒,刷新页面,我被重定向到登录页面,并显示我的会话超时的消息。当我再次登录用户时,我被重定向到常见问题页面,除了上面显示的几个步骤之外没有任何其他代码。

    流程是这样的(你可能比我更了解):检查用户是否登录 -> 如果没有,则重定向。现在重定向与 :timeoutable 模块没有任何关系。 :timeoutable 模块 'simply' 倒计时并检查用户会话是否有效,如果不是,它会在后台注销用户。如果用户想再次尝试该页面,它使用 :authenticate_user!方法,检查用户是否登录,如果没有,那么,重定向他。

    看起来像您的身份验证用户!没有按应有的方式工作。您是否尝试过(正在开发中)更新设计?

    我强烈建议您使用设计创建一个超级简单的应用程序,然后重做上面的步骤,看看它是否按您想要的方式工作。

    据我所知,redirect_url 部分通常由设计在幕后注入。

    我曾经为一个应用定制了它,去config/initializers/devise.rb

    进入Devise.setup |config|

    require "custom_path"
    
    config.warden do |manager|
      manager.failure_app = CustomPath
    end
    

    lib/custom_path.rb

    class CustomPath < Devise::FailureApp
      def redirect_url
        ## redirect to wherever you want
      end
    end
    

    就是这样。然后设计将重定向到您想要的任何页面。

    无论如何,很高兴您仍然可以通过调整中间件中的某些部分来解决问题。

    您好!

    【讨论】:

    • 感谢您的解释。所以我的问题确实是错误的设置。它实际上与设计本身无关。设计依赖于 Warden,而 Warden 依赖于存在的 Cookie 和 Session 中间件。在我的情况下,Cookie 和 Session 中间件没有出现在正确的位置,这破坏了 Warden,然后破坏了 Devise。将这些中间件放在正确的位置可以修复它。但是我关于重定向到attempted_path 的问题仍然存在。我可能会单独提出。
    • 太棒了,你肯定能搞定这个。我认为在设计 github 上开一张票是你最好的选择。问候!
    猜你喜欢
    • 1970-01-01
    • 2020-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多