2016-06-28 30 views
0

My Rails應用程序採用面向公衆的形式,通過AJAX將用戶輸入作爲字符串化的JSON傳遞給控制器​​。該表單專爲脫機使用而設計,因此每次訪問除第一頁以外的表單頁面都是通過瀏覽器緩存(使用緩存清單)提供的。我有一個問題,表單提交返回一個422 unprocessable entity錯誤,除非在導航到表單頁面之前瀏覽器歷史記錄已被清除......也就是說用戶只能進行一個表單提交,所有後續提交內容爲422,除非他們清除歷史並返回到表單來刷新緩存。不幸的是,這不會飛。Rails/AJAX緩存表單提交 - 422無法處理的實體

我對Rails的安全性並沒有太大的經驗,但我的印象是這與CSRF保護有關,而且對於除第一個表單頁之外的任何訪問,一個陳舊的CSRF標記正在通過。

我的AJAX請求看起來就像這樣:

$.ajax({ 
    url: "post/submission", 
    type: "POST", 
    dataType: "json", 
    beforeSend: function(xhr) {xhr.setRequestHeader("X-CSRF-Token", $("meta[name='csrf-token']").attr("content"))}, 
    data: {"post" : postParameter}, 
    success: function(response){ 
     window.location = '/post/approval'; 
    } 
}); 

目前,佈局頁包含<%= csrf_meta_tags %>,我必須在應用程序控制器標準protect_from_forgery with: :exception

需要注意這種形式的最終結構件是,雖然表單本身是面向公衆的,它需要用戶登錄後,點擊提交按鈕 - 所以提交將沒有有效的登錄成功。

有沒有一種安全的方法可以解決這個問題?我相信這一點不言而喻,但我不能讓我的用戶在每次提交後清除歷史記錄並重新緩存表單。

+0

如果您想要保持CSRF保護,則必須在呈現表單時重新生成令牌。 '<%= hidden_​​field_tag:authenticity_token,form_authenticity_token%>'這樣做。從緩存中顯示頁面時的ajax調用會執行。查看更多[here](http://stackoverflow.com/questions/8503447/rails-how-to-add-csrf-protection-to-forms-created-in-javascript)和[here](http:// stackoverflow .COM /問題/ 829046 /怎麼辦 - 我 - 檢測 - 如果-A-用戶已經-了到一個頁面,使用最後退按鈕)。 –

+0

嗯......我應該提到的另一件事是,表單不是以標準的Rails方式與表單助手等構建的。事實上,表單並非HTML表單中的一種表單 - 在提交時,用戶輸入被編譯成一個JSON字符串,然後通過AJAX將其解析出來並插入到數據庫中...所以這裏沒有一個地方可以放置一個'hidden_​​field_tag'。我認爲在你加入的第二個鏈接中可能有一些很好的解決方案 - 我會測試它們,並讓你知道我是否可以得到任何東西。感謝您的時間。 – skwidbreth

+0

當然,您只需將'form_authenticity_token'的結果傳遞給您的前端,而不管它是作爲模板呈現的一部分完成還是通過ajax調用傳輸。從那裏你可以將它包含到你的POST負載中。 –

回答

1

爲了在提交來自JavaScript的POST請求時保持CSRF保護,您需要在表單的有效內容或請求標頭中提供當前身份驗證令牌。

當頁面從瀏覽器緩存中加載時,其身份驗證令牌可能已過時,因此需要從後端刷新頁面。一種方法是檢測"page loaded from browser cache"事件並運行一個ajax請求來獲取新的令牌,後者應該由form_authenticity_token方法生成。

接收到的認證令牌可以用於後續的JavaScript POST請求。例如,描述了檢測從緩存中加載的頁面的技術,例如, in this StackOverflow answer

相關問題