LoginSignup
87
57

More than 5 years have passed since last update.

【Rails API】ActionController::InvalidAuthenticityTokenの解決方法

Last updated at Posted at 2019-01-24

現在、APIを用いたタスク管理アプリを作成しているものです。
標記のとおりのエラーがでましたので、解決方法とエラーの原因について整理したいと思います。

環境

Ruby 2.4.1
Ruby on Rails 5.2.2
Node.js 6.15.1
yarn 1.13.0
Webpacker 3.0.2
Vue.js 2.4.3

ソースコード及びエラー内容

ソースコード

controllers/api/tasks_controller.rb

class Api::TasksController < ApplicationController

  # GET /tasks
  def index
    @tasks = Task.order('updated_at DESC')
  end

  # POST /tasks
  def create
    @task = Task.new(task_params)

    if @task.save
      render :show, status: :created
    else
      render json: @task.errors, status: :unprocessable_entity
    end
  end

  # PATCH/PUT /tasks/1
  def update
    @task = Task.find(params[:id])
    if @task.update(task_params)
      render :show, status: :ok
    else
      render json: @task.errors, status: :unprocessable_entity
    end
  end

  private
    # Never trust parameters from the scary internet, only allow the white list through.
    def task_params
      params.fetch(:task, {}).permit(
          :title, :important , :urgent
      )
    end
end

views/api/tasks/index.json.jbuilder

json.set! :tasks do
  json.array! @tasks do |task|
    json.extract! task, :id, :title, :important, :urgent
  end
end

views/api/tasks/show.json.jbuilder

json.set! :task do
  json.extract! @task, :id, :title, :important, :urgent
end

routes.rb

Rails.application.routes.draw do
    root to: 'home#index'

    namespace :api, format: 'json' do
      resources :tasks, only: [:index, :create, :update]
    end 
end

エラー内容

curlコマンドで新規APIの追加をしようとしたところ、だだだーっと意味不明なコードが流れました。

$ curl -X POST localhost:8080/api/tasks -d 'task[title]=fugafuga'(エラー)

ログをみてみるとこのような表示がされました。

ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):

有効ではないトークンみたいな感じでしょうか。

解決方法

CSRFの対応について、rails使いが知っておくべきこと
RailsのCSRF対策について
外部からPOSTできない?RailsのCSRF対策をまとめてみた

を参考にさせていただきました。

ソースコードを以下のように変更します。

cotrollers/api/tasks_controller

class Api::TasksController < ApplicationController
protect_from_forgery #追記
(略)

結果、表示することができました!

 $ curl -X POST localhost:8080/api/tasks -d 'task[title]=fugafuga'
{"task":{"id":11,"title":"fugafuga","important":null,"urgent":null}}

なぜこのようなことが起きるのか?

railsはデフォルトでaplication.controller.rbにprotect_from_forgeryメソッドが定義されています。

これはCSRF(Cross-Site Request Forgery)の対策です。
CSRFは、簡単に言うと、悪意のあるユーザーがサーバーへのリクエストを捏造して正当なものに見せかけ、認証済みユーザーを装うという攻撃手法です。(詳しくは→RailsのCSRF保護を詳しく調べてみた(翻訳))

railsにおいては、ユーザーがPOSTリクエストをした際に、ページに埋め込まれているCSRFトークンを生成し、cookieにあるトークンを同一のものかを確認します。

railsは、get以外の動詞のリンクに、authenticity_tokenというパラメータを自動的に付け加えます。get以外の動詞の各アクションでparams[:authenticity_token]とsession[:csrf_id]を比較して、同値であればOKとしているようです。*1同値でなければActionController::InvalidAuthenticityTokenという例外がでます。

私の場合、なぜかprotect_from_forgeryが定義されていなかったので、新規で外部からPOSTしようとすると、エラーがでてしまいました。

今日のエラーは以上です。
なにか間違いがありましたらご指摘ください。

87
57
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
87
57