RailsでAPIサーバを作るときにフロントエンド・アプリケーションとの連携で出てきがちなCORSの設定。
毎回調べるのがめんどくさいので、セキュリティ要件的にもテキトウにするわけにはいかないこのCORSの**「とりあえずこれだけやっておけばOK」**な設定をRailsとJavaScriptの実装と一緒に説明します。
CORSとは?
CORSは日本語ではHTTPアクセス制御のことで、簡単に言うと許可されていないウェブサイトからのアクセスをブロックすることで悪意のあるアクセスを防ぐための機構です。
rack-cors
を導入
この記事では、デフォルトでRailsのアプリケーションの中に生成されるconfig/initializers/cors.rb
というファイルに従って、rack-corsを使います。
まずはGemfileに以下を追記して、rack-corsをインストール
gem 'rack-cors'
環境変数でAllowed Originを指定できるようにする
本番環境と開発環境でそれぞれ許容するドメインを柔軟に変更できるよう、CORS_ALLOWED_ORIGINS
の環境変数を指定する形で、APIへのアクセスを許容するドメインを指定します。
config.x.cors_allowed_origins = ENV.fetch('CORS_ALLOWED_ORIGINS', 'http://localhost:8000')
ENV.fetch
のフォールバック(ここではlocalhost:8000
)は適宜指定してください。
CORSの設定
上で設定したconfig.x.cors_allowed_origins
を、許可するドメインとして指定します。
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('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サーバへのアクセス制御を行えるようになります。
以上です。