Rails8 認証ジェネレータ機能
なぜ今になって認証ジェネレータが追加されたのか
Railsの認証用gemとして使われるdeviseは初心者にはおすすめできない
すでにRailsには認証用のメソッド(has_secure_passwordなど)認証用のメソッドを用意しているが部品だけの形で提供されているため使い方が分かりにくい
どのように組み合わせるとよいかの道を示すためのツールとして認証ジェネレータを作った
あくまでシンプルな認証機能の使い方を示すもので、すべての認証ユースケースを解決するためのものではない
認証ジェネレータから生成されるコードを知ることでセキュリティを学ぶことにつながる
現時点でジェネレータが提供されている機能
メールアドレスとパスワードのログイン
ログアウト
パスワードリセット
ログイン回数の制限
提供されていない機能
サインアップ
メール認証
など
認証ジェネレータで生成されるもの
モデル
User
Session
ユーザーのログイン状態を管理するためのモデル
Current
ログインユーザーにCurrent.userでアクセスするためのモデル(CurrentAttributes)
コントローラー
SessionsController
ログイン・ログアウト用
PasswordsController
パスワードリセット用
concern
認証関連のヘルパーメソッド
ログインの流れ
https://gyazo.com/22ba6a56fe2622a61d7a7c76180983ce
https://techracho.bpsinc.jp/hachi8833/2024_10_21/145343 より
code:ruby
class SessionsController < ApplicationController
allow_unauthenticated_access only: %i new create
rate_limit to: 10, within: 3.minutes, only: :create, with: -> { redirect_to new_session_path, alert: "Try again later." }
def new
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
def destroy
terminate_session
redirect_to new_session_path, status: :see_other
end
end
User.authenticate_by はUserモデルの has_secure_password を呼ぶことで追加されるメソッド
https://github.com/rails/rails/blob/main/activemodel/lib/active_model/secure_password.rb#L123
has_secure_passwordの主な機能
ユーザー作成次のパスワードをBCryptでハッシュ化して格納
ユーザー作成時のパスワードのバリデーションを追加
ログイン時のパスワード比較用のメソッドを追加
has_secure_passwordはもともとある(Rails3で追加された)機能
yana-gi.iconhas_secure_password 機能が何ができるか別途まとめたい
パスワードのハッシュ化
code:ruby
myapp(dev):001> user = User.new(password: 'password')
myapp(dev):002> user.password_digest
=> "$2a$12$dNfEjFkM9xa6wWlxO/bxiexeRMCCTzzrq8YQYAg/N0VhX9UiG.nda"
start_new_session_for user がログインするためのメソッド
code:ruby
# app/controllers/concerns/authentication.rb
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
Sessionがレコードとして存在している=ログイン状態を成立させる条件の一つ
code:ruby
# ログインしている状態でSessionのレコードを見る
myapp(dev):003> Session.all
Session Load (10.7ms) SELECT "sessions".* FROM "sessions" /* loading for pp */ LIMIT 11 /*application='Myapp'*/
=>
[#<Session:0x0000000105a59a78
id: 2,
user_id: 1,
ip_address: "127.0.0.1",
user_agent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Ap...",
created_at: "2025-10-26 05:25:58.198977000 +0000",
updated_at: "2025-10-26 05:25:58.198977000 +0000">]
yana-gi.icon ?cookiesセッションとの違い
yana-gi.icon sessionは物理削除してる📝
Currentモデル
code:ruby
class Current < ActiveSupport::CurrentAttributes
attribute :session
delegate :user, to: :session, allow_nil: true
end
スレッドごとに分かれているリクエストのたびにリセットされるグローバル変数
code:ruby
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
ここでsessionではなくcokkiesを利用しているのはAction Cableで利用するため
Action Cableはsessionを使えない
パスワードリセットの流れ
https://gyazo.com/ef1040b8bc60db054fa549a9f9e5c750
https://techracho.bpsinc.jp/hachi8833/2024_10_21/145343 より
code:ruby
class PasswordsController < ApplicationController
allow_unauthenticated_access
before_action :set_user_by_token, only: %i edit update
def edit
end
def update
if @user.update(params.permit(:password, :password_confirmation))
# パスワード更新が成功したら該当ユーザーのセッションを全部失効させる(セッション乗っ取り対策)
@user.sessions.destroy_all
redirect_to new_session_path, notice: "Password has been reset."
else
redirect_to edit_password_path(params:token), alert: "Passwords did not match."
end
end
private
def set_user_by_token
@user = User.find_by_password_reset_token!(params:token)
rescue ActiveSupport::MessageVerifier::InvalidSignature
redirect_to new_password_path, alert: "Password reset link is invalid or has expired."
end
end
参考
Rails 8で基本的な認証ジェネレータが導入される(翻訳)|TechRacho by BPS株式会社
rails g authenticationから学ぶRails8\.0時代の認証 \- Speaker Deck
Rails 認証 セキュリティ