Devise中的InvalidAuthenticityToken :: SessionsController#destroy(已经注销后退出)

时间:2014-03-18 17:56:24

标签: ruby-on-rails exception devise csrf

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

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

提出异常:

  

ActionDetroller :: Devise中的InvalidAuthenticityToken :: 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'

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

7 个答案:

答案 0 :(得分:10)

以下是发生的事情,

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

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

每次登录只能获得一个唯一的会话,如果它被破坏,你将无法再次销毁。

修改

Devise不提供此行为。如果您希望实现此类行为,则必须覆盖SessionsController。

sessions_controller.rb目录

中创建app/controllers/users文件
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" }

答案 1 :(得分:5)

这个问题的简单解决方案也可以允许通过GET而不是DELETE进行注销。在devise.rb中,您只需更改为:

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

答案 2 :(得分:2)

将其粘贴在布局中:       <%= csrf_meta_tags%>

答案 3 :(得分:1)

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

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

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

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

这样,使用默认策略。

答案 4 :(得分:1)

此错误已在devise 3.3.0修复。

答案 5 :(得分:0)

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

答案 6 :(得分:0)

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

protect_from_forgery with: :exception

protect_from_forgery with: :null_session
希望它有所帮助。