【问题标题】:Invalid Authenticity Token on Post帖子上的真实性令牌无效
【发布时间】:2016-03-19 00:15:48
【问题描述】:

我正在使用devise 注册/登录。

路线

get 'profile' => 'profile#get_profile'
post 'profile' => 'profile#create_profile'

profile_controller

def get_profile
    render json: {user: current_user}, status: :ok
end

def create_profile
    render json: {user: current_user}, status: :ok
end

GET: http://localhost:3000/user/profile 返回预期的输出。然而,

POST 请求抛出错误:

ActionController::InvalidAuthenticityToken in User::ProfileController#create_profile.

请揭开这种行为的神秘面纱。

【问题讨论】:

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


【解决方案1】:

要禁用CSRF protection,您可以像这样编辑您的ApplicationController

class ApplicationController < ActionController::Base
  protect_from_forgery with: :null_session

  # ...
end

或禁用特定控制器的CSRF protection

class ProfilesController < ApplicationController
  skip_before_action :verify_authenticity_token

  # ...
end

:null_session 策略清空会话而不是引发异常非常适合 API。因为会话是空的,所以不能使用current_user 方法或引用session 的其他助手。

重要提示

  • protect_from_forgery with: :null_session 只能用于特定的 情况,例如允许没有 html 表单的 API 请求(POST/PUT/PATCH/DELETE)
  • 使用protect_from_forgery with: :null_session,您必须使用授权系统限制对数据的访问,因为每个人都可以针对您的 API 端点提出请求
  • 不要删除通过 html 表单完成的请求的 protect_from_forgery with: :exception很危险!(阅读此处http://guides.rubyonrails.org/security.html#cross-site-request-forgery-csrf

要处理标准请求(通过 html 表单)和 API 请求,通常您必须为同一资源设置两个不同的控制器。示例:

路线

Rails.application.routes.draw do
  resources :profiles

  namespace :api do
    namespace :v1 do
      resources :profiles
    end
  end

end

应用控制器

# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception
end

ProfilesController

(html 请求的标准控制器)

# app/controllers/profiles_controller.rb
class ProfilesController < ApplicationController

  # POST yoursites.com/profiles
  def create
  end
end

Api::V1::ProfilesController

(API 请求的控制器)

# app/controllers/api/v1/profiles_controller.rb
module Api
  module V1
    class ProfilesController < ApplicationController
      # To allow only json request
      protect_from_forgery with: :null_session, if: Proc.new {|c| c.request.format.json? }

      # POST yoursites.com/api/v1/profiles
      def create
      end
    end
  end
end

推荐人: http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection/ClassMethods.html#method-i-protect_from_forgery

【讨论】:

  • 我暂时禁用了 CSRF 保护。什么时候进行protect_from_forgery::null_session 我无法从会话中获取current_user。
  • @Emmy protect_from_forgery with: :null_session 在每个请求期间提供一个空会话,或者更确切地说,您不能使用引用 sessioncurrent_user 方法或助手,因为它是空的。我编辑了我的答案,试图更好地解释不同的情况。
  • @Imran 正如 NickGnd 所概述的那样,我认为需要强调这一点:您需要获得授权和授权,以确保流氓 API 发布请求不会对您的应用造成任何损害。
【解决方案2】:

获取请求没有真实性令牌。

您必须使用此方法将请求伪造内容添加到您的表单中

<%= csrf_meta_tag %> 

并通过 javascript 寻址

$('meta[name="csrf-token"]')

【讨论】:

  • 我还没有创建任何表单,我正在做后端只在浏览器中呈现 json 输出。
  • 不管你说什么我都明白了,但有没有其他方法可以解决它,因为我没有前端部分。
【解决方案3】:

ApplicationController(或您的控制器继承自的另一个控制器)中有一行:

protect_from_forgery with: :exception

删除它,CSRF 检查将被禁用。

【讨论】:

  • 不要这样做。它在那里是有原因的。您将打开应用程序以应对 CSRF 攻击。
  • @gregblass null_session 与完全删除protect_from_forgery 行有何不同?
猜你喜欢
  • 2019-06-20
  • 2018-06-29
  • 2010-11-15
  • 1970-01-01
  • 1970-01-01
  • 2018-06-20
  • 2017-03-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多