9
6

More than 1 year has passed since last update.

【Rails】APIモードかつクロスオリジン間でCookieやSessionを使う方法【SPA】

Last updated at Posted at 2022-07-21

環境

  • Ruby 3.1.2
  • Rails 6.1.6
  • Vite 2.9.9
  • Vue 3.2.25
  • Google Chrome (バージョン:103.0.5060.53)

前提

  • RailsはAPIモードで使用
  • フロントエンドとバックエンド間は異なるオリジンでの通信

やり方

APIモードで起動したRailsはそのままではCookieを使うことができません。
なので、まずCookieを使うことができるようにします。

app/controllers/application_controller.rb
class ApplicationController < ActionController::API
  include ActionController::Cookies # 追加
config/application.rb
module App
  class Application < Rails::Application
    # ...
    config.middleware.use ActionDispatch::Cookies # 追加
    # セッションを使う場合は以下も追加しておく
    # config.middleware.use ActionDispatch::Session::CookieStore
  end
end

これでCookieを使うことができるようになるのですが、
フロントエンドとバックエンドでオリジンが異なる場合、
RailsでCookieをセットしてもブラウザに反映されないと思います。

よってさらに以下の設定を追加します。
ここでは、フロントエンドのオリジンがhttp://localhost:3000
バックエンドのオリジンがhttp://localhost:8000の開発環境を想定することにします。

CORS設定に credentials: true を追加する

config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins 'http://localhost:3000'

    resource '/api/v1/*',
      headers: :any,
      methods: [:get, :post, :put, :patch, :delete, :options, :head],
      credentials: true # 追加
  end
end

gem 'rack-cors'を使用したCORS設定については下記の記事に説明があるので下記を参考にしてみてください。

フロントエンド側のaxiosの設定に withCredentials: true を追加する

src/plugins/axios.ts
const axiosInstance: AxiosInstance = axios.create({
  baseURL: "http://localhost:8000/api/v1",
  headers: {
    "Content-type": "application/json",
  },
  withCredentials: true // 追加
})

※Fetch API等のaxios以外のHTTP通信を使用している場合は下記の記事を参考にしてみてください。

これで開発環境でCookieが使えるようになると思います。
ただし、本番環境ではさらにやるべきことがあります。

開発環境ではフロントエンドとバックエンドでポート番号のみの違いしかないですが、
本番環境ではフロントエンドのオリジンはhttps://www.hogehoge.com
バックエンドのオリジンはhttps://api.hogehoge.comといったようなドメイン自体が異なるといった構成になると思います。
その場合、フロントエンドとバックエンドはクロスサイトという扱いになり、
CookieのSameSite属性をNoneにしなければなりません。

よってさらに以下の設定を追加します。

CookieのSameSite属性をNoneにする設定を追加する

config/application.rb
module App
  class Application < Rails::Application
    # ...
    config.middleware.use ActionDispatch::Cookies
    config.action_dispatch.cookies_same_site_protection = :none # 追加
  end
end

※cookies_same_site_protectionはRails6.1から新規追加された設定らしいので
Rails6.1未満の場合は下記の記事を参考にgem 'rails_same_site_cookie'を使って設定してみてください。

SameSite属性をNoneにした場合は、CookieのSecure属性も付与しなければいけません。

CookieのSecure属性を追加する。

cookieをセットしている箇所にsecure: trueを追加します。

cookies[:hoge] = { value: 'piyo', http_only: true, secure: true }

本番環境をSSL化する

Secure属性が付加されたCookieはHTTPS通信でしか送信されないため
本番環境をSSL化してあげましょう。

これで本番環境でもCookieが使えるようになっていると思います。

Secure属性付けたら開発環境もSSL化しないといけないの?

localhostの場合のみSecure属性のCookieでもHTTPで送信できるため、
開発環境をSSL化する必要はないみたいです。

とのことなので、開発環境・本番環境関わらずここまでの設定を一度にやっておくのが良いと思います。

参考

【Rails】APIモードでcookieを使う
クロスオリジンでcookieの挙動を確認する
Railsガイド(ミドルウェアスタックの内部)

9
6
0

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
9
6