Ruby on Rails 6.x + Omniauth でRedisのSessionを使う
Ruby on Rails5.2以降、 Redisのキャッシュ機能を標準サポートされました。
Rails の OAuth2 クライアントとして Omniauthを使った場合、 無策で実装するとCSRFエラーが出ます。
OmniAuth::Strategies::OAuth2::CallbackError (csrf_detected | CSRF detected):
これはOmniauthが Railsとは別の Rackアプリケーションとして立ち上がっていて、Railsの設定を読まないためです。 公式サイトにはCookieセッションでの対応方法が書いてありますが、Redisで設定する場合の記述がなされていません。
手順
1. Redis stores for ActionPack のGemをインストールする
Rails上でRedisのSessionを使うのはもちろん、 ActionDispatch::Session::RedisStore
を使うのに必要です。
Gemfile
gem 'redis-actionpack'
2. Rails の Session設定を書く
/config/initializers/session_store.rb
Rails.application.config.session_store :redis_store, servers: [ENV.fetch("REDIS_URL")], key: ENV.fetch("REDIS_SESSION_KEY"), expire_after: 1.month, threadsafe: true, signed: false, secure: Rails.env == 'production' ? true : false
3. Omniauth の Session設定を書く
Rackアプリケーションの設定でミドルウェアでSessionを読むようにします。
ここでRailsと同じ設定を書かなければSessionがつながりません。DRYじゃないので悔しいですが、同じ記述をします。
/config/application.rb
module App class Application < Rails::Application config.load_defaults 6.0 config.session_store :redis_store, servers: [ENV.fetch("REDIS_URL")], key: ENV.fetch("REDIS_SESSION_KEY"), expire_after: 1.month, threadsafe: true, signed: false, secure: Rails.env == 'production' ? true : false config.middleware.use ActionDispatch::Cookies # Required for all session management config.middleware.use ActionDispatch::Session::RedisStore, config.session_options # ~以下略~ end end
これで動くはずです。
ハマリどころ
NoMethodError (undefined method
private_id' for nil:NilClass): redis-rack (2.1.3) lib/rack/session/redis.rb:49:in
block (2 levels) in write_session'
上記のエラーが出る場合、Rackミドルウェアの読み込みで ActionDispatch::Session::RedisStore
がオプションを正常に受け取っていない(or 間違っている)ところ疑うと良いです。
ここでめちゃくちゃハマりました。
config.middleware.use ActionDispatch::Session::RedisStore, config.session_options
そういうわけで、やっていきましょう。