【问题标题】:Rails 4 delete button logs me out and results in "Can't verify CSRF token authenticity"Rails 4 删除按钮将我注销并导致“无法验证 CSRF 令牌真实性”
【发布时间】:2015-05-26 21:27:59
【问题描述】:

我正在运行 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>

我的开发日志告诉我这是因为它“无法验证 CSRF 令牌的真实性”。我似乎可以让它工作的唯一方法是从删除按钮更改为发布到删除操作的表单,但这有点愚蠢。我已经在其他 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 令牌没有与此请求一起发送,就像它在表单中一样。

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

更新:这是来自 development.log 的 sn-p

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

【问题讨论】:

  • 您可能缺少对 Rails UJS 的正确 JavaScript 支持。你确定你已经正确加载了application.js?
  • 是的,我在里面有//= require jquery_ujs
  • 任何不寻常的 JavaScript 错误?您的 POST 请求是否看起来不错,就像它包含 CSRF 令牌一样?网络检查器在这里提供帮助。
  • 你能显示你的日志吗?
  • 网络面板中的一切看起来都不错,302 响应,正在发送带有隐藏输入 _method: "delete" 的 POST。

标签: ruby-on-rails ruby-on-rails-4 devise


【解决方案1】:

使用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>

【讨论】:

  • 我会接受的。它仍然会产生一种形式,但至少它是一个衬里。我仍然对为什么 link_to 不起作用感到困惑。我知道它不提供 csrf 令牌,但我过去曾这样做过。也许它适用于 Rails 3 而不是 Rails 4?
  • Ryan,你的head 标签中有= csrf_meta_tags 吗? (编辑:我意识到你确实在上面提到过它。我很确定在 Rails 4 中仍然需要 jQuery UJS 在非 GET 请求上发送真实性令牌。)
  • 叹息。在使用 button_to 解决方案完成所有工作后,我看到了您的回复,并认为我会尝试将 csrf_meta_tags 添加到头部,果然,它现在可以工作了。感谢您让我仔细检查,我更喜欢这个解决方案。
  • 在看到你的第一条评论后,我去检查我自己的应用程序,果然,我使用a 标记用于使用方法的注销按钮:删除。进一步挖掘使我检查 csrf 标签是否仍在使用。很高兴你解开了这个谜!
  • 对,我知道我有其他应用程序使用标签作为删除方法,这就是为什么我把头撞在墙上的原因。
【解决方案2】:

您必须将 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”是一种返回 CSRF 令牌的约定方法。这将对请求进行身份验证。

【讨论】:

    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 2014-07-04
      • 2016-02-27
      • 2014-06-16
      • 2017-07-15
      • 2015-07-24
      • 2018-03-31
      • 2012-05-08
      • 2015-12-29
      • 2023-03-26
      相关资源
      最近更新 更多