【发布时间】:2020-09-16 00:25:41
【问题描述】:
我有一个如下所示的表单:
<%= form_with(url: star.starname, method: :post, local: true) do |f| %>
<% star.availabilities.each do |avail| %>
<%= f.label avail.time_slot %>
<%= radio_button_tag(:time_slot, avail.time_slot) %> <br>
<% end %>
<%= f.submit "Create" %>
<% end %>
表单提交后立即:
注意事项:
- 这发生在应用程序(不是 API)中,因此会话很重要,因此必须保持 CSRF 保护。
- 问题出现在 chrome、incognito 和 safari 中。
- 我已尝试使用不同的用户登录并清除 cookie(以防它是由 stale token 引起的)
更多错误信息:
Started POST "/talljohn" for ::1 at 2020-09-16 10:06:21 +1000
Processing by StarsController#book as HTML
Parameters: {"authenticity_token"=>"P++4a+giwUBqZgCLfMwqKpMu0EGitd8zTOi5RWsnxpKlNcjiuU6hd3ebbIC/IOxlL74RJIvrq+yDuA1ZtfcvFw==", "time_slot"=>"2020-09-16 01:00:00 UTC", "commit"=>"Create", "starname"=>"talljohn"}
Can't verify CSRF token authenticity.
Completed 422 Unprocessable Entity in 1ms (ActiveRecord: 0.0ms | Allocations: 655)
ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):
actionpack (6.0.3.2) lib/action_controller/metal/request_forgery_protection.rb:215:in `handle_unverified_request'
actionpack (6.0.3.2) lib/action_controller/metal/request_forgery_protection.rb:247:in `handle_unverified_request'
devise (4.7.2) lib/devise/controllers/helpers.rb:255:in `handle_unverified_request'
actionpack (6.0.3.2) lib/action_controller/metal/request_forgery_protection.rb:242:in `verify_authenticity_token'
activesupport (6.0.3.2) lib/active_support/callbacks.rb:428:in `block in make_lambda'
activesupport (6.0.3.2) lib/active_support/callbacks.rb:200:in `block (2 levels) in halting'
actionpack (6.0.3.2) lib/abstract_controller/callbacks.rb:34:in `block (2 levels) in <module:Callbacks>'
activesupport (6.0.3.2) lib/active_support/callbacks.rb:201:in `block in halting'
更新
我恢复到表单的最后一个工作版本,它与上面完全相同,但没有, local: true。然后它突然起作用了! (没有错误)。
我以为local: true(或remote: false)只是关闭了ajax 表单提交。所以我不明白为什么这会产生任何影响(或与 CSRF 有任何关系),这两个方面似乎是不相关的,不清楚为什么这两个概念会相互影响
更新 2
我后来意识到另一个未触及的以前工作的表单也产生了这个错误。它没有以任何方式改变。我在chrome incognito中尝试过,它产生了错误。半小时后(不更改任何代码)我在同一个浏览器中再次尝试它并且它工作。这种(非常)奇怪的行为让我觉得这与会话、cookie 或缓存有关。如果我有任何进一步的了解,我会回来报告
更新 3
在阅读Sarah's solution 后将protect_from_forgery prepend: true 添加到应用程序控制器(我在before_action :authenticate_user! 之前和之后都尝试过),日志中出现相同的错误消息,POST 请求未执行,但应用程序重定向到主页。 IE。在发布后我看到:
Can't verify CSRF token authenticity.
Completed 401 Unauthorized in 1ms (ActiveRecord: 0.0ms | Allocations: 444)
Started GET "/users/sign_in" for ::1 at 2020-09-17 21:08:42 +1000
Processing by Devise::SessionsController#new as HTML
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
Redirected to http://localhost:3000/
Filter chain halted as :require_no_authentication rendered or redirected
Completed 302 Found in 3ms (ActiveRecord: 0.5ms | Allocations: 1900)
更新 4
我尝试手动清除 Rails 片段缓存(使用 Rails.cache.clear )。但是清除片段缓存之前/之后的结果是完全一样的。
【问题讨论】:
-
您是否尝试过添加
<%= hidden_field_tag :authenticity_token, form_authenticity_token %>?您不必这样做,但它可能会在故障排除方面提供一些价值 -
会不会是缓存相关的?我曾经遇到过类似的问题,这是由于在布局中使用片段缓存 csrf 元标记引起的。
-
@NMPennypacker 我没有那个隐藏字段(除了问题表格中的内容)。但是私有方法看起来像这样:
params.permit(:authenticity_token, :time_slot, :starname, :commit) -
@max 我怀疑缓存可能是原因。所以我尝试了隐身,以不同的用户身份登录,并清除 cookie。还有什么要尝试的吗?
-
片段缓存独立于客户端,同样适用于任何反向代理缓存。它基本上是服务器为每个客户端提供相同的陈旧内容。
标签: ruby-on-rails ruby-on-rails-6