🐡

Ruby on RailsでのCORS対策

に公開

はじめに

社内の開発では、全てRuby on Railsでの開発をしており、個人開発をする際はバックエンドをRailsにして何か作ろうと思ったのでその際の備忘録です。
今回は、Ruby on Railsをバックエンドに、Reactをフロントエンドに使ったプロジェクトで少し詰まったCORSについての話とRailsでどう実装するのか、またAxiosを使ったAPIリクエスト時に発生するネットワークエラーについて解決したいと思います。

1. CORSとは?

CORS(Cross-Origin Resource Sharing)は、異なるオリジン間でリソースを共有するための仕組みです。
通常、ブラウザはセキュリティ上、異なるオリジン間のリクエストをブロックしますが、CORSヘッダーを正しく設定することで特定のオリジンからのアクセスを許可することができます。
今回であるとバックエンドはlocalhost://3000であり、フロントエンドはlocalhost://3001になるので、フロントエンドからデータを送った場合(リクエスト)にバックエンドからデータの結果(レスポンス)が帰ってきた場合に異なるオリジンという扱うを受けるため、ブロックされます。

シーケンス


@startuml

User ->> Frontend: ユーザー情報をフォームに入力
Frontend ->> Backend: OPTIONS /api/register\nOrigin: http://localhost:3001\nAccess-Control-Request-Method: POST\nAccess-Control-Request-Headers: Content-Type
Backend -->> Frontend: HTTP/1.1 204 No Content\nAccess-Control-Allow-Origin: http://localhost:3001\nAccess-Control-Allow-Methods: POST\nAccess-Control-Allow-Headers: Content-Type

Frontend ->> Backend: POST /api/register\nOrigin: http://localhost:3001\nContent-Type: application/json\n{email: user@example.com, password: ******}
Backend -->> Frontend: HTTP/1.1 201 Created\nAccess-Control-Allow-Origin: http://localhost:3001\nContent-Type: application/json\n{message: "User created successfully"}

Frontend -->> User: 登録完了メッセージ表示
@enduml

参考資料:

[https://developer.mozilla.org/ja/docs/Web/HTTP/CORS:title]

オリジンとは以下の3つの要素で構成されています:

  • プロトコル(例:httphttps
  • ドメイン(例:example.com
  • ポート番号(例:80443

これらの一つでも異なれば、異なるオリジンという扱いをされています。例えば、https://example.comhttp://example.comは異なるオリジンです。

2. Ruby on RailsでのCORS設定

Ruby on RailsでCORSを設定するには、rack-corsというGemを使用します。このGemを使うことで、RailsアプリケーションにCORSヘッダーを簡単に設定できます。

2.1 rack-corsのインストール

まず、Gemfileにrack-corsを追加します。

gem 'rack-cors'

その後、以下のコマンドでインストールします。

bundle install

2.2 CORS設定の追加

次に、config/application.rbにCORSの設定を追加します。ここで、特定のオリジンからのリクエストを許可するように設定します。

module YourApp
  class Application < Rails::Application
    config.middleware.insert_before 0, Rack::Cors do
      allow do
        origins 'https://your-frontend-domain.com'
        resource '*',
          headers: :any,
          methods: [:get, :post, :put, :patch, :delete, :options, :head],
          credentials: true
      end
    end
  end
end
  • origins: 許可するオリジンを指定します。
  • resource: リクエストできるリソースを指定します。*はすべてのリソースを許可します。
  • headers: 許可するリクエストヘッダーを指定します。:anyはすべてのヘッダーを許可します。
  • methods: 許可するHTTPメソッドを指定します。
  • credentials: クッキーや認証情報を含むリクエストを許可するかどうかを指定します。

3. Axiosでのリクエスト

ReactのフロントエンドからRuby on RailsのバックエンドにAPIリクエストを送る際、Axiosを使用します。このとき、認証情報(クッキーなど)を含めるためにwithCredentialsオプションを設定する必要があります。

3.1 Axiosのリクエスト例

以下のコードは、ユーザー登録時にAPIリクエストを送信する例です。


axios.post('http://localhost:3000/auth', {
  email: 'test@gmail.com',
  password: 'testtest',
  password_confirmation: 'testtest',
  confirm_success_url: 'http://localhost:3000/signin'
}, {
  withCredentials: true  // クッキーを含めるための設定
})
.then(response => {
  console.log(response.data);
})
.catch(error => {
  console.error('Error:', error);
});

ここで、withCredentials: trueを設定することで、ブラウザはクッキーをリクエストに含めます。このオプションを使用する場合、サーバー側でもcredentials: trueの設定が必要です。
多分これでできるはず

Discussion