📖

Rails8.0の認証機能生成コマンドについて

2024/11/08に公開

はじめに

Rails8がリリースされました 🎉
Rails7.2 -> Rails8ではさまざまな変更がありますが、外部のPaaSに依存しないスタンドアロンで実行するためのライブラリをデフォルトでRailsに組み込んでいるという変更が主になっている印象があります

たとえば

  • デプロイツールであるKamal2
  • Redisの代替としてのSolid Cable
  • Memcachedの代替としてのSolid Cache
  • Nginxの代替としてのプロキシThurster
  • Sidekiqの代替としてのSolid Queue

https://rubyonrails.org/2024/11/7/rails-8-no-paas-required

それと合わせて認証についてもアップデートがあるので
ここだけに絞って見ていこうかなと思います。

deviseを使うのとどっちがいいんですかね〜

何ができるのか

  • 認証周りの機能
  • ログイン処理のView, Controller, Routingを自動生成
  • パスワードリセット処理のView, Controller, Routingを自動生成
  • has_secure_passwordのみでパスワードリセットをデフォルトで利用できるように

手順

rails new

新しいRailsプロジェクトを作っていきます。

bash
rails new rails-eight-sample

./bin/rails generate authentication

  • 認証の処理の追加
bash
./bin/rails generate authentication

差分

usersテーブル、モデルが追加された

2024XXXXXXXXXX_create_users.rb
# 認証のためのユーザテーブル追加
class CreateUsers < ActiveRecord::Migration[8.0]
  def change
    create_table :users do |t|
      t.string :email_address, null: false
      t.string :password_digest, null: false

      t.timestamps
    end
    add_index :users, :email_address, unique: true
  end
end
app/models/user.rb
class User < ApplicationRecord
  # このオプションによって model.password_reset_token を使って一時トークンを発行することができる
  # password_reset_token はメールのViewの中で呼ばれている
  has_secure_password
  has_many :sessions, dependent: :destroy

  normalizes :email_address, with: ->(e) { e.strip.downcase }
end

sessionsテーブル、モデルが追加された

2024XXXXXXXXXX_create_sessions.rb
# 認証のためにsessionsテーブルを追加
class CreateSessions < ActiveRecord::Migration[8.0]
  def change
    create_table :sessions do |t|
      t.references :user, null: false, foreign_key: true
      t.string :ip_address
      t.string :user_agent

      t.timestamps
    end
  end
end
app/models/session.rb
class Session < ApplicationRecord
  belongs_to :user
end
config/routes.rb
Rails.application.routes.draw do
  # この2行が追加された
  resource :session
  resources :passwords, param: :token

  ...
end

認証系の処理はconcerns下に追加された

app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  # この行が追加され、app/concerns/authentication.rb をincludeしている
  include Authentication

  ...
end

ログイン画面、パスワード変更画面

  • Viewは省略します
config/routes.rb
Rails.application.routes.draw do
  # この2行が追加された
  resource :session
  resources :passwords, param: :token

  ...
end

ログインユーザを示すモデルの追加

app/models/current.rb
# ログイン中のユーザを取得するため
class Current < ActiveSupport::CurrentAttributes
  attribute :session
  delegate :user, to: :session, allow_nil: true
end

その他

ViewやMailerなどが追加されましたが省略します

メールの設定

パスワードリセット時にメールが送られてくるので、それをローカルで確認できるようにメール周りの設定をします

compose.ymlを準備

  • パスワードリセット用のリンクを確認するためにmailhogコンテナを用意する
compose.yml
services:
  mailhog:
    image: mailhog/mailhog:latest
    ports:
      - "8025:8025"
      - "1025:1025"

ローカル開発時にmailhogにメールを送るよう設定

config/environments/development.rb
require "active_support/core_ext/integer/time"

Rails.application.configure do
  ...

  # 以下を追記する
  config.action_mailer.smtp_settings = { address: "127.0.0.1", port: 1026 }
  config.action_mailer.raise_delivery_errors = true
  config.action_mailer.delivery_method = :smtp

データ追加

Userデータを追加します。

seeds.rb
User.create!(email_address: "foo@example.com", password: "password")
User.create!(email_address: "bar@example.com", password: "password")
User.create!(email_address: "baz@example.com", password: "password")

ログイン後のルーティングとページを作成

ルーティング

config/routes.rb
Rails.application.routes.draw do
  ...
  root "users#index"
  ...
end

ページ

app/views/users/index.html.erb
<ul>
  <% @users.each do |user| %>
    <li><%= user.email_address %></li>
  <% end %>
</ul>

動作確認

ログイン画面にアクセス

パスワードリセット画面にアクセス

  • メールアドレスを入力し、Resetを押す

リセットを押した後はログイン画面に戻ってくる

メールを確認

  • リンクからリセットページに飛ぶ

パスワード変更画面でパスワード入力

変更が完了するとログイン画面に戻ってくる

備考

有効期限を変えたい時

app/models/user.rb
class User < ApplicationRecord
  has_secure_password
  # ここで override すると有効期限等を変えられる
  generates_token_for :password_reset, expires_in: 30.seconds

  ...
end

まとめ

  • password_reset_tokenviews/passwords_mailer/reset.html.erbで呼ばれているため、どこで一時トークンを生成しているかわかりづらかった
  • 2FA等はまだ出来ないので、deviseの代替になるかと言われると難しい
    • 2FAの求められないアプリケーションならdeviseなくてもいいかもしれない
Politive Tech Blog

Discussion