ITスタートアップCTOによるITエンジニアのためのブログ

Rails組み込み認証とDeviseの比較

Ruby on Railsの認証システムといえば Devise gemが有名ですが、実はRailsには has_secure_passwordauthenticate_by メソッドを使う認証システムがデフォルトで組み込まれています。さらに Rails 8 では、待望の認証機能ジェネレータが追加され、認証基盤の構築がよりスムーズになりました。

本記事では、Rails 8の新機能を中心に、組み込み認証とDeviseを比較・解説します。

結論

機能の豊富さでは依然としてDeviseに軍配が上がりますが、標準的な認証フローであればRails組み込み機能で十分に事足ります。 Gemへの依存を減らせるメリットは大きいため、要件に合わせて選択するのがベストです。

目次

  • Rails 8の認証機能ジェネレータ(rails generate authentication)
  • 新規ユーザ作成とhas_secure_password
  • authenticate_byによるログイン機能
  • パスワードリセット機能
  • Devise gemとの比較
  • まとめ

Rails 8の認証機能ジェネレータ(rails generate authentication)

Rails 8では、認証に必要なボイラープレート(定型コード)を一括生成するコマンドが追加されました。

# 新しいRailsアプリの作成
rails new rails8_auth_app
cd rails8_auth_app

# 認証機能ジェネレータの実行
bin/rails generate authentication

このコマンドにより、以下の主要なファイルが生成されます。

  • Authentication コンサーン(コントローラでの認証状態管理)
  • User / Session モデル
  • SessionsController(ログイン・ログアウト)
  • PasswordsController(パスワードリセット)

最後にマイグレーションを実行します。

bin/rails db:migrate

注) Rails 8のセッション管理 生成される Session テーブルは、ユーザーエージェントやIPアドレスを記録するだけでなく、「特定のセッションを無効化する」ために使用されます。これにより、複数の端末でログインしている場合に、特定の端末からのみログアウトさせるといった高度な管理が標準で可能になっています。

新規ユーザ作成とhas_secure_password

Railsコンソールで動作を確認してみましょう。

user = User.create(
  email_address: 'hoge@example.com',
  password: 'your_password',
  password_confirmation: 'your_password')

この時、パスワードのバリデーションや bcrypt によるハッシュ化を担うのが User モデルに記述された has_secure_password です。

class User < ApplicationRecord
  has_secure_password
  has_many :sessions, dependent: :destroy

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

has_secure_passwordRails 3.1 から存在する歴史ある機能です。ジェネレータがなかった以前のバージョンでも、このメソッドを軸に自作認証を構築するのが定番の手法でした。

authenticate_byによるログイン機能

Rails 7.1で追加された authenticate_by を使うと、ログイン処理が非常に安全かつ簡潔に記述できます。

class SessionsController < ApplicationController
  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
end

authenticate_by はタイミング攻撃(実行時間の差からパスワードの推測を試みる攻撃)への対策が施されており、セキュリティ面でも信頼が置けます。

動作確認

ログイン機能を検証するにはログイン後の遷移ページが必要なので、例としてPagesコントローラーを作成し、 ルートパスに指定します。

# config/routes.rb
Rails.application.routes.draw do
  ...
  root "pages#index"
end
# app/controllers/pages_controller.rb
class PagesController < ApplicationController
  def index; end
end

Viewにはログインしていたらログアウトボタンを、ログアウトしていたらログインリンクを表示するようにします。

# app/views/pages/index.html.erb
<% if authenticated? %>
  <%= button_to "Sign Out", session_path, method: :delete  %>
<% else %>
  <%= link_to "Sign In", new_session_path %>
<% end %>

Railsサーバーを起動します。

bin/rails server

この状態で、https://engineerjutsu.com:3000/session/newにアクセスすると、SessionsController#newが実行されログインフォームが表示されます。

ログインフォーム

先ほど作成したユーザーのログイン情報を使ってログインフォームを送信するとSessionsController#createが実行されます。

ここで、authenticate_byメソッドでメールアドレスとパスワードの組み合わせが検証され、成功すればセッションレコードがDBに作成されてログイン状態になります。

ログイン後は先ほど作成したPagesController#indexにリダイレクトされます。ログアウトボタンが表示されるので、無事にログインできていることがわかります。

ログアウトボタン

ログアウトボタンを押すとSessionsController#destroyが実行され、セッションレコードやCookieが削除されます。

パスワードリセット機能

Rails 8のジェネレータは、パスワードリセットの仕組みも標準で生成します。

  1. リセット要求: ユーザーがメールアドレスを入力。
  2. メール送信: 署名付きID(Signed ID)を含むリンクを送信。
  3. 再設定: リンクの有効期限内であれば、新しいパスワードを設定可能。

これまでは ActiveSupport::MessageVerifier などを使って自作していた部分が、最初から組み込まれているのは大きな進歩です。

動作確認

ログインフォーム上の「Forgot password?」リンクをクリックすると、PasswordsController#new が実行され、パスワードリセットフォームが表示されます。

パスワードリセットメール送信フォーム

先ほど作成したユーザのメールアドレスを入力して送信すると、PasswordsController#createが実行され、パスワードリセットリンクを含むEメールが送信された旨のメッセージが表示されます。

パスワードリセットメール送信
メッセージ

同時に、PasswordsMailer#resetが実行され、以下の画像のようなパスワードリセットメールが送信されます。

パスワードリセットメール

メール内のパスワードリセットリンクをクリックするとアプリケーションに遷移し、PasswordsController#editが実行され、パスワードリセットフォームが表示されます。

パスワードリセットフォーム

新しいパスワードを入力して送信すると、PasswordsController#updateが実行され、パスワードがリセットされます。

パスワードリセットメッセージ

Devise gemとの比較

Rails 8の組み込み認証と、高機能なDeviseを比較してみましょう。

機能DeviseモジュールRails 8 認証ジェネレータ
パスワードハッシュ化Database Authenticatable✅ あり(has_secure_password)
ユーザー登録Registerable⚠️ モデルのみ(コントローラ等は自作)
パスワードリセットRecoverable✅ あり
メール確認Confirmable❌ なし(自作が必要)
ログイン維持Rememberable✅ あり(Permanent Cookie)
アカウントロックLockable❌ なし
外部認証(OAuth)Omniauthable❌ なし
タイムアウトTimeoutable❌ なし
トラッキングTrackable⚠️ 一部(アクティブセッションのIPアドレスやユーザーエージェント)
バリデーションValidatable⚠️ パスワードのみ(メールアドレスフォーマットは自作)

Rails組み込み認証のメリット

  • ブラックボックス化の解消: 全てのコードが app/ 配下に生成されるため、カスタマイズが容易。
  • メンテナンス性: Rails本体のアップデート時にGemの互換性を心配する必要がない。
  • 軽量性: 不要な機能が含まれず、アプリがシンプルに保てる。

Deviseのメリット

  • 多機能: 2段階認証やソーシャルログインなど、複雑な要件を素早く実装できる。
  • 実績: 膨大なコミュニティによる知見があり、周辺の拡張Gemも豊富。

まとめ

Rails 8の認証ジェネレータの登場により、「とりあえずDeviseを入れる」という時代から、「まずは標準機能で作り、必要に応じて拡張する」という選択ができるようになりました。

シンプルなBtoBアプリや個人開発ならRails組み込み認証で十分ですし、逆に「最初からフル機能が欲しい」という商用サービスならDeviseが向いています。まずは一度、bin/rails generate authentication を叩いて、生成されるコードを読んでみることをおすすめします!