Edited at

これだけでイイ、Rails5でAPIサーバを作るときのCORS設定

More than 1 year has passed since last update.

RailsでAPIサーバを作るときにフロントエンド・アプリケーションとの連携で出てきがちなCORSの設定。

毎回調べるのがめんどくさいので、セキュリティ要件的にもテキトウにするわけにはいかないこのCORSの「とりあえずこれだけやっておけばOK」な設定をRailsとJavaScriptの実装と一緒に説明します。


CORSとは?

CORSは日本語ではHTTPアクセス制御のことで、簡単に言うと許可されていないウェブサイトからのアクセスをブロックすることで悪意のあるアクセスを防ぐための機構です。


rack-corsを導入

この記事では、デフォルトでRailsのアプリケーションの中に生成されるconfig/initializers/cors.rbというファイルに従って、rack-corsを使います。

まずはGemfileに以下を追記して、rack-corsをインストール


Gemfile

gem 'rack-cors'



環境変数でAllowed Originを指定できるようにする

本番環境と開発環境でそれぞれ許容するドメインを柔軟に変更できるよう、CORS_ALLOWED_ORIGINSの環境変数を指定する形で、APIへのアクセスを許容するドメインを指定します。


config/application.rb

config.x.cors_allowed_origins = ENV.fetch('CORS_ALLOWED_ORIGINS', 'http://localhost:8000')


ENV.fetchのフォールバック(ここではlocalhost:8000)は適宜指定してください。


CORSの設定

上で設定したconfig.x.cors_allowed_originsを、許可するドメインとして指定します。


config/initializers/cors.rb

Rails.application.config.middleware.insert_before 0, Rack::Cors do

allow do
origins Rails.application.config.x.cors_allowed_origins

resource '*',
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options, :head],
credentials: true
end
end



JavaScript側の実装

とりあえず下のコードを使えばOK

ここではFetch APIを使った、Railsで実装されたAPIサーバとは異なるSPAなどのフロントエンド・アプリケーションからのアクセスを想定しています。


fetchを使ったAPIアクセス

fetch('http://your-api-server.net', {

mode: 'cors',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
})
.then((res) => ...)

大事なのはcredentials: 'include'のところで、たとえばSPAなどで認証情報をクッキーなどで渡すためにSet-Cookieなどを使うためには、必ずこの指定が必要になります。


アプリケーションの起動

上で触れたように、今回のRailsアプリケーションはCORS_ALLOWED_ORIGINSで指定されたドメインのみを許可します。なので、例えばAPIサーバを開発用にローカルで起動する際には、そのAPIサーバへアクセスするフロントエンド・アプリケーションのドメインとポートの指定が必要です。

たとえば、localhost:8000でローカルにフロントエンド・アプリケーションが起動しているのであれば

$ CORS_ALLOWED_ORIGINS=http://localhost:8000 bundle exec rails server

とすることで、ローカル上でフロントエンド・アプリケーションからAPIサーバへのアクセスがCORSを有効にしながら行えるようになります。

本番でもCORS_ALLOED_ORIGINSの環境変数をセットしてやることで、APIサーバへのアクセス制御を行えるようになります。

以上です。