Deviseでフレンドリーフォワーディングを実装する
前置き
Railsでの認証に Devise を使っている人は多いと思います。
ただ、 Devise はデフォルトではフレンドリーフォワーディングが効いていません。
フレンドリーフォワーディングとは、ユーザーが認証前に開こうとしていたページへ、認証後にリダイレクトさせることです。
参考: Rails チュートリアル
最近機会があったので、DeviseのHow Toを参考に実装しました。
その際にやったことを残しておきます。
なお、各バージョンは以下の通りです。
- Ruby 2.3.1
- Rails 4.2.7.1
- Devise 3.5.1
手順
アクセスされたURLを保存する
認証前にアクセスしようとしたページをセッションに保存します。
current_user
が取得できれば認証できているので、その場合は除外しています。
また、 devise_controller
の各アクションの場合も除外しています。
# app/controllers/application_controller.rb
before_action :store_current_location, unless: :devise_controller?
private
def store_current_location
return if current_user
store_location_for(:user, request.url)
end
store_location_for
を呼ぶと、session[:user_return_to]
にURLを保存してくれます。
:user
の部分は認証のscopeです。大抵の場合は :user
でOKかと思います。
実は、フレンドリーフォワーディングの実装としてはこれだけで完了です。
session[:user_return_to]
にURLが入っていると、認証後にリダイレクトしてくれるようです。
ただ、セキュリティ対策として以下の場合は追加の対応が必要です。
認証後にセッションをリセットする場合
Rails ガイド のセキュリティのページで、セッション固定攻撃の対応策 について紹介されています。
ログイン認証の際に、 reset_session
を行なうというものです。
これを行なうと、当然上で保存したURLも消えてしまうので、その値だけ別途引き継ぐ対応を行ないます。
user_return_to
を引き継ぐ
Devise::SessionsController
を継承したControllerで以下の対応をします。
# app/controllers/sessions_controller.rb
before_action :reset_session_before_login, only: :create
private
def reset_session_before_login
user_return_to = session[:user_return_to]
reset_session
session[:user_return_to] = user_return_to if user_return_to
end
これで、認証時の reset_session
をしつつフレンドリーフォワーディングをすることが可能になりました。