環境
- 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を使うことができるようにします。
class ApplicationController < ActionController::API
include ActionController::Cookies # 追加
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 を追加する
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 を追加する
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にする設定を追加する
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ガイド(ミドルウェアスタックの内部)