Rails 4 删除按钮将我注销并导致 "Can't verify CSRF token authenticity"

Rails 4 delete button logs me out and results in "Can't verify CSRF token authenticity"

我是 运行 Rails 4.2、Devise 3.4.1 和 CanCan 1.6.10。当我尝试通过如下所示的标准删除按钮删除资源时,我被注销并重定向到登录页面。

<a data-confirm="Are you sure?" class="btn-alert" rel="nofollow" data-method="delete" href="/admin/lots/6">Delete</a>

我的开发日志告诉我这是因为 "Can't verify CSRF token authenticity"。我似乎可以让它工作的唯一方法是从删除按钮更改为 posts 到删除操作的表单,但这有点愚蠢。我已经在其他 Rails 4 个应用程序中这样做了,所以我很确定我做对了。

index.html.erb

<% if can? :destroy, lot %>
   <%= link_to "Delete", admin_lot_path(lot.id), method: :delete, data: {confirm: "Are you sure?"}, class: 'btn-alert' %>
<% end %>

lots_controller.rb

class Admin::LotsController < ApplicationController
  before_filter :authenticate_user!
  load_and_authorize_resource

  def destroy
    @lot.destroy
    redirect_to admin_lots_path, notice: "Lot was successfully removed."
  end
end`

正如我所说,用表单替换按钮似乎可行,但这并不理想。

<%= form_for([:admin, lot], method: :delete) do |f| %>
   <%= f.submit value: "Delete", class: 'btn-standard', data: {confirm: "Are you sure?"} %>
<% end %>

如果我从控制器中注释掉 before_filter :authenticate_user!load_and_authorize_resource,它就可以工作。我假设 csrf 令牌没有像在表单中那样与此请求一起发送。

有人知道我可以尝试什么吗?如果有帮助,愿意 post 更多代码。顺便说一句,我的应用程序中的所有删除都会发生这种情况。

更新:这是来自development.log

的片段
Started DELETE "/admin/lots/6" for 127.0.0.1 at 2015-05-26 15:03:22 -0500
Processing by Admin::LotsController#destroy as HTML
  Parameters: {"id"=>"6"}
Can't verify CSRF token authenticity

使用 button_to 而不是 link_to

button_to "Delete", admin_lot_path(lot.id), method: :delete, data: {confirm: "Are you sure?"}, class: 'btn-alert'

link_to 生成缺少真实性令牌的 HTML,

<a data-confirm="Are you sure?" class="btn-alert" rel="nofollow" data-method="delete" href="/admin/lots/6">Delete</a>

button_to 产生

<form class="button_to" method="post" action="/admin/lots/6">
    <input type="hidden" name="_method" value="delete">
    <input data-confirm="Are you sure?" class="btn-alert" type="submit" value="Delete">
    <input type="hidden" name="authenticity_token" value="1QajBKKUzoEtUqi6ZX8DsQtT9BfvKY/WVXAr4lu4qb+iLGMkLlsviNcctlGxyq+VrsMa+U9vmb4PAdaRFDKZVQ==">
</form>

您必须将 csrf 令牌作为参数传递,示例:

link_to "Delete", admin_lot_path(id: lot.id, authenticity_token: form_authenticity_token), method: :delete, data: {confirm: "Are you sure?"}, class: 'btn-alert'

"form_authenticity_token" 是 returns CSRF token 的约定方法。这将验证请求。

根据 ActionController documentation 所有控制器操作都受到 CSRF(跨站请求伪造)攻击的保护,因此您需要在呈现的 HTML 中包含您的令牌,或者另一种方式是包含 protect_from_forgery unless: -> { request.format.json? } 在您的 应用程序控制器 中。这个问题不会出现在 GET 请求中,因为你没有在那里操作数据,而是出现在 POST,DELETE,PATCH 方法中.