【问题标题】:InvalidAuthenticityToken in Devise::SessionsController#destroy (sign out after already having signed out)Devise::SessionsController#destroy 中的 InvalidAuthenticityToken(已注销后注销)
【发布时间】:2014-04-24 14:26:27
【问题描述】:

我正在使用 Devise 3.2.0 进行身份验证,但在执行以下操作时发现了一个问题:

  • 标签 1:登录到应用
  • 标签 2:转到应用中的任何页面
  • 标签 2:退出退出(成功)
  • 标签 1:退出 (失败 - 请参阅下面的例外情况)

引发异常:

ActionController::InvalidAuthenticityToken in Devise::SessionsController#destroy

在开发日志中我看到:

无法验证 CSRF 令牌的真实性

堆栈跟踪的前三行是:

ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):
  actionpack (4.0.0) lib/action_controller/metal/request_forgery_protection.rb:163:in `handle_unverified_request'
  actionpack (4.0.0) lib/action_controller/metal/request_forgery_protection.rb:170:in `handle_unverified_request'
  devise (3.2.0) lib/devise/controllers/helpers.rb:198:in `handle_unverified_request'

如何确保连续退出不会引发异常?

【问题讨论】:

  • 它不是连续退出,当您已经退​​出时,您正在尝试退出。那么,当您从 tab2 注销时,为什么不从 tab1 注销用户
  • 我不知道你为什么说这不是连续退出。 连续意味着一个接一个。如果我在退出另一个选项卡后尝试在一个选项卡中退出,就我而言,这是连续的。但关键是,这是用户可以采取的非常合理的操作。举一个例子,用户在一个站点上打开多个标签页,当他们在一个标签页中退出,然后继续关闭其他标签页时,他们可能会尝试再次退出(由于登录的外观所有其他选项卡)。
  • @user664833 现在我明白了。是的,Devise 应该已经处理了注销场景而不会引发讨厌的错误。但同样,他们可能会说这就是我们所说的customization。在 Devise 实施之前,KirtiThorat 的解决方法可能是更好的解决方案。
  • 在 Devise Github Repo 上查看 @freddyrangel github.com/plataformatec/devise/issues/2934 提交的问题。您可以通过支持该问题来参与讨论。

标签: ruby-on-rails exception devise csrf


【解决方案1】:

这是发生了什么,

当您最初从选项卡 2 注销时,与已登录用户关联的 session 和authentity_token 已被销毁。 当您尝试从选项卡 1 注销时,Devise 再次尝试使用在选项卡 2 上销毁的authentity_token 销毁会话。

因此,您会收到错误 ActionController::InvalidAuthenticityToken,因为设计无法使用给定的 authenticity_token 进行身份验证。

每次登录您只能获得一个独特的会话,如果该会话被破坏,您将没有任何东西可以再次破坏。

编辑

Devise 不提供此行为。如果你想实现这样的行为,你必须重写 SessionsController。

app/controllers/users目录下创建sessions_controller.rb文件

class Users::SessionsController < Devise::SessionsController
  prepend_before_filter :verify_user, only: [:destroy]

  private
  ## This method intercepts SessionsController#destroy action 
  ## If a signed in user tries to sign out, it allows the user to sign out 
  ## If a signed out user tries to sign out again, it redirects them to sign in page
  def verify_user
    ## redirect to appropriate path
    redirect_to new_user_session_path, notice: 'You have already signed out. Please sign in again.' and return unless user_signed_in?
  end
end

更新routes.rb

devise_for :users, :controllers => { :sessions => "users/sessions" }

【讨论】:

  • 谢谢。我了解为什么会发生这种情况,但我想知道如何在不引发异常的情况下使其工作。例如,如果您在 Twitter 或几乎任何其他网站上执行相同的操作,则所有连续的注销尝试都会成功 - 只要没有引发异常,并使用户相信他们刚刚签名退出(不管他们实际上已经退出)。
  • @KirtiThorat 我认为如果用户收到一条消息会更好,例如“您已经退出,请重新登录”然后重定向到登录页面而不是root_path。
  • @user3317140 +1 这听起来是个好主意。将其添加到代码中。
  • @KirtiThorat 看起来不错。您(或 @freddyrangel)应向 Devise 提交针对此解决方法的拉取请求。
【解决方案2】:

Kirti 完全正确。我昨天遇到了这个问题,但是使用了自定义身份验证解决方案。如果这确实是您想要解决的问题,您可以弄清楚如何覆盖 Devise 的注销操作并为该操作添加 skip_before_filter :verify_authenticity_token

【讨论】:

  • 是的,我意识到我可以覆盖 Devise 的注销操作,但我很惊讶 Devise 还没有正确处理这件事,因为这不是不常见的用户行为。令我惊讶的是,Devise 会将这个松散的结局留给开发人员来解决。这种行为在任何方面是如何令人满意的?
  • 你说得很好。实际上,我实际上可能会提交一个拉取请求。
  • 谢谢你 - 请做。 IE。如果用户已经退出,​​则绕过通常的代码,让它看起来好像用户现在退出了。
  • @freddyrangel 如果您有解决方法,请提交拉取请求。这种默认的不良行为必须消失
  • 我已经在 github 上提交了一个问题,看看之前是否已经解决了。我的感觉是,Devise 窥视者在安全性方面真的很重要,所以他们可能不会继续尝试可能会或可能不会危及安全性的事情。
【解决方案3】:

您可以更改验证 csrf 令牌的策略。

在 rails 3 中,验证失败时的默认策略是返回一个空会话。在 rails 4 中更改了 application_controller 中的策略以返回异常。

我解决了这个问题,更改了我的 application_controller.rb

class ApplicationController < ActionController::Base
-    protect_from_forgery, with: :exception
+    protect_from_forgery

这样,使用默认策略。

【讨论】:

    【解决方案4】:

    解决此问题的一个简单方法是允许通过 GET 而不是 DELETE 退出。在 devise.rb 中,您可以简单地更改为:

    # The default HTTP method used to sign out a resource. Default is :delete.
    config.sign_out_via = :get
    

    【讨论】:

    【解决方案5】:

    此错误已在 devise 3.3.0 中修复。

    【讨论】:

      【解决方案6】:

      如果您仍然像我在Rails 5devise 4.4.1 中那样遇到此问题,请在 app/controllers/application_controller.rb 中更改

      protect_from_forgery with: :exception
      

      protect_from_forgery with: :null_session
      

      希望对你有帮助。

      【讨论】:

        【解决方案7】:

        将其粘贴到布局中:

        【讨论】:

          猜你喜欢
          • 2014-12-17
          • 2019-07-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-10-23
          • 1970-01-01
          • 2017-01-05
          相关资源
          最近更新 更多