Rails8から新しく認証ジェネレータが追加されました。このジェネレータは、認証周りのシステムを自動で生成してくれるもので、基本的な機能がかなり充実しています。
自動で生成される処理
- セッション管理
- 認証処理
- パスワードリマインダー
※上記機能に紐づくRoutingやModelの追加も自動で行われます。
今回は、この認証ジェネレータを実際に試してみた内容をまとめました。
認証ジェネレータの詳しい情報が知りたい方はRails 8で基本的な認証ジェネレータが導入される(翻訳)をご覧ください。
環境
- rails8.0.1
- ruby3.2.6
通常のRails環境を準備したのち、以下の手順で実行しました。
-
rails generate authentication
コマンドを実行 -
rails db:migrate
コマンドを実行 - サーバーを起動
生成されたページを見てみる
生成されたViewはとても簡素で、最低限のフォームとルーティングが用意されています。
ログイン画面
/session/new
にアクセスすると、以下のようなログインページが表示されます。
ユーザー作成について
デフォルトでは、新規アカウント作成フローは提供されていません。ユーザー作成が必要な場合は、自力で実装する必要があります。
今回はコード上で仮のユーザーを作成し、その情報を使ってログインしました。
パスワードリマインダー
/passwords/new
にアクセスすことで、パスワードリマインダーのページにアクセスできます。
フォームSubmit処理にはMailerが利用されています。ローカルで試す場合はmailhog
やletter_opener
などのツールを導入する必要があるでしょう。
コードを見て印象的だったこと
1. 各種コントローラーでの認証チェック方法
ApplicationController
にAuthentication
モジュールがincludeされており、このコントローラーを継承した他のコントローラーでは、認証チェックが自動的に行われます。
そのため、追加の実装なしで認証済みユーザー専用のアプリケーションを開発できます。
class ApplicationController < ActionController::Base
include Authentication
# Only allow modern browsers supporting webp images, web push, badges, import maps, CSS nesting, and CSS :has.
allow_browser versions: :modern
end
認証をスキップする方法
特定のアクションで認証をスキップしたい場合は、以下のように記述できます。
allow_unauthenticated_access only: [:index]
2. アクセス時のURLがログイン後に引き継がれる
未ログイン状態でユーザーがアクセスした場合、セッションにアクセス元のURLが保存されます。
ログイン成功時には保存されたパスにリダイレクトされる仕組みとなっています。
def request_authentication
session[:return_to_after_authenticating] = request.url
redirect_to new_session_path
end
...
def after_authentication_url
session.delete(:return_to_after_authenticating) || root_url
end
def create
if user = User.authenticate_by(params.permit(:email_address, :password))
start_new_session_for user
redirect_to after_authentication_url
else
redirect_to new_session_path, alert: "Try another email address or password."
end
end
3. 認証ロジックのまとめ方
ジェネレータが生成するconcerns/authentication.rb
には、認証に必要なロジックがスマートにまとめられています。
module Authentication
extend ActiveSupport::Concern
included do
before_action :require_authentication
helper_method :authenticated?
end
class_methods do
def allow_unauthenticated_access(**options)
skip_before_action :require_authentication, **options
end
end
private
def authenticated?
resume_session
end
def require_authentication
resume_session || request_authentication
end
def resume_session
Current.session ||= find_session_by_cookie
end
def find_session_by_cookie
Session.find_by(id: cookies.signed[:session_id]) if cookies.signed[:session_id]
end
def request_authentication
session[:return_to_after_authenticating] = request.url
redirect_to new_session_path
end
def after_authentication_url
session.delete(:return_to_after_authenticating) || root_url
end
def start_new_session_for(user)
user.sessions.create!(user_agent: request.user_agent, ip_address: request.remote_ip).tap do |session|
Current.session = session
cookies.signed.permanent[:session_id] = { value: session.id, httponly: true, same_site: :lax }
end
end
def terminate_session
Current.session.destroy
cookies.delete(:session_id)
end
end
コードは読みやすく整理されており、認証の基本を学ぶ良い参考資料になると感じました。
おわりに
認証ジェネレータは、認証に必要な基本的な機能をシンプルに実装できる便利なツールです。
実際のプロジェクトではそのまま適用するのが難しい場合もあるかもしれませんが、生成されるコードはリファクタリングや構造設計の参考になります。
ブラックボックスな部分が増えてしまうGemとは異なり、独自でカスタマイズしやすいのもジェネレータのいい点だと思います。
認証機能に初めて触れる方や、新しいプロジェクトで試してみたい方は、ぜひ利用してみてください!