2014-03-18 43 views
8

我使用Devise3.2.0進行身份驗證,發現當我做了以下的問題:InvalidAuthenticityToken在設計:: SessionsController#破壞(登出已經有退出後)

  • 標籤1:登錄以應用
  • 標籤2:去任何頁面的應用
  • 片2:簽署(成功)
  • 標籤1:簽出(失敗 - 見下文除外)

發生異常:

的ActionController :: InvalidAuthenticityToken在設計:: SessionsController#破壞

在開發日誌我看到:

無法驗證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' 

我如何能確保連續標誌出局沒有引發異常?

+0

它不是連續登出,你想退出,當你已經登出。所以爲什麼不從tab1註銷用戶,當你從tab2登出 –

+0

我不知道你爲什麼說這是*不是*連續註銷。 *連續*表示*相互連接*。如果我在退出另一個選項卡後嘗試退出,那麼就我而言,這是連續的。但問題是,這是用戶可以採取的非常合理的行動。一個例子是,用戶在單個網站上打開多個標籤,當他們在一個標籤中註銷,然後繼續關閉其他標籤時,他們可能會嘗試再次退出(由於已登錄所有其他標籤)。 – user664833

+0

@ user664833現在我明白了。是的,Devise應該已經處理了註銷方案而不會引發令人討厭的錯誤。但是,他們也許會說這就是我們所說的「定製」。在Devise實現它之前,KirtiThorat的解決方法可能是更好的解決方案。 – HackerKarma

回答

10

這裏是發生了什麼,

當你最初從標籤2,會議簽署並authenticity_token與登錄用戶被破壞有關。 當您嘗試從標籤1註銷,設計再次嘗試使用這是對標籤破壞2.

因此,authenticity_token摧毀會話,你得到的錯誤ActionController::InvalidAuthenticityToken爲色器件故障使用給定authenticity_token進行身份驗證。

每次登錄您只會得到一個獨特的會話,如果這個會被破壞,您將無法再次銷燬。

編輯

此行爲不是由設計提供。如果你想實現這種行爲,你將不得不重寫SessionsController。

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" } 
+0

謝謝。我明白*爲什麼會發生這種情況,但我想知道*如何在不引發異常的情況下使其工作*。例如,如果您在Twitter或幾乎任何其他網站上執行相同的操作,則所有連續註銷嘗試都會成功 - 只要不*引發例外情況,並且讓用戶相信他們剛剛退出(不管事實上*他們實際上已經簽出*)。 – user664833

+0

@ user664833查看我更新的答案。 –

+1

@KirtiThorat我認爲如果用戶得到一個flash消息會更好。 「您已經退出,請重新登錄」,然後重定向到登錄頁面而不是root_path。 – HackerKarma

0

基爾提創建一個sessions_controller.rb文件是完全正確的。我昨天遇到了這個問題,但使用了自定義驗證解決方案。如果這確實是您想要解決的問題,那麼您可以瞭解如何重寫Devise的註銷操作併爲該操作添加skip_before_filter :verify_authenticity_token

+0

是的,我意識到我可以重寫Devise的註銷操作,但我很驚訝這還沒有被Devise正確處理,因爲它不是一個不常見的用戶行爲。令我感到驚訝的是,Devise將爲開發人員解決這個問題留下一個鬆散的結局。這種行爲在*任何*方式中是如何令人滿意的? – user664833

+0

你說得很好。實際上,我可能會提交拉取請求。 – freddyrangel

+0

謝謝 - 請做。即如果用戶已經*退出,那麼繞過通常的代碼,並使其看起來好像用戶現在已經退出。 – user664833

1

您可以更改驗證csrf令牌的策略。

在rails 3中,驗證失敗時的默認策略是返回空會話。在rails 4中,更改了application_controller中的策略以返回一個異常。

我解決這個問題,在我的application_controller.rb

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

這種方式改變,使用默認的策略。

5

這個問題的簡單解決方案也可以通過GET而不是DELETE來註銷。在devise.rb中,您可以簡單地更改爲:

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

沒有在Rails 4.1.10中工作,Devise> = 3.3.0 – CodeWalrus

+0

@CodeWalrus,根據最新的提交,它似乎沒有爲初始化文件更改任何內容。你確定這不是一個不同問題的結果嗎? https://github.com/plataformatec/devise/blob/868d3d82a014509167ccd7dd3e794171011bffe1/lib/generators/templates/devise.rb#L240 – Peleg