📖
Rails8.0の認証機能生成コマンドについて
はじめに
Rails8がリリースされました 🎉
Rails7.2 -> Rails8ではさまざまな変更がありますが、外部のPaaSに依存しないスタンドアロンで実行するためのライブラリをデフォルトでRailsに組み込んでいるという変更が主になっている印象があります
たとえば
- デプロイツールである
Kamal2
- Redisの代替としての
Solid Cable
- Memcachedの代替としての
Solid Cache
- Nginxの代替としてのプロキシ
Thurster
- Sidekiqの代替としての
Solid Queue
それと合わせて認証についてもアップデートがあるので
ここだけに絞って見ていこうかなと思います。
devise
を使うのとどっちがいいんですかね〜
何ができるのか
- 認証周りの機能
- ログイン処理のView, Controller, Routingを自動生成
- パスワードリセット処理のView, Controller, Routingを自動生成
-
has_secure_password
のみでパスワードリセットをデフォルトで利用できるように-
generates_token_for
はRails7.1に登場した -
generates_token_for
の内部実装について
-
手順
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>
動作確認
ログイン画面にアクセス
- http://localhost:3000/session/new
- forgot passwordを入力
パスワードリセット画面にアクセス
- メールアドレスを入力し、Resetを押す
リセットを押した後はログイン画面に戻ってくる
メールを確認
- リンクからリセットページに飛ぶ
パスワード変更画面でパスワード入力
変更が完了するとログイン画面に戻ってくる
備考
有効期限を変えたい時
app/models/user.rb
class User < ApplicationRecord
has_secure_password
# ここで override すると有効期限等を変えられる
generates_token_for :password_reset, expires_in: 30.seconds
...
end
まとめ
-
password_reset_token
がviews/passwords_mailer/reset.html.erb
で呼ばれているため、どこで一時トークンを生成しているかわかりづらかった - 2FA等はまだ出来ないので、deviseの代替になるかと言われると難しい
- 2FAの求められないアプリケーションならdeviseなくてもいいかもしれない
Discussion