Sorcery gemでRailsに認証機能を実装する手順|Deviseとの違い・最新0.18.0対応
Sorceryは、Ruby on Railsに最小構成で認証機能を組み込む軽量なgemです。ログイン・ログアウトやパスワード管理といった基本フローだけを提供し、足りない部分は自分のコードで書き足す設計になっています。本記事はこのRails認証gem「Sorcery」の実装手順を扱います(英単語sorcery=魔術やゲームブック『ソーサリー』の解説ではありません)。最新は0.18.0で、Rails 7.1以上(railties 7.1+)が動作要件です。
まとめ:Sorceryを使う前に押さえる要点
- Sorceryは「認証の土台だけ提供し、画面や制御は自作する」方針のgem。全部入りのDeviseより薄く、カスタマイズ前提の中小規模向け。
- 最新は0.18.0(MITライセンス)。依存はbcrypt・oauth・oauth2で、Rails 7.1以上が必要。
- 導入は「Gemfile追加 →
rails g sorcery:install→rails db:migrate→ Userモデルにauthenticates_with_sorcery!」の4ステップ。 - ログイン判定は
login/logout/logged_in?/require_loginで行う。未認証時の挙動はnot_authenticatedを上書きして制御する。 - パスワードリセット・アカウントロック・メール認証・OAuthはsubmoduleを宣言して有効化する。外部連携は
submodules = [:external]の宣言漏れが最頻の失敗。
Sorceryとは|Railsの軽量認証gem
Sorceryは、ユーザー認証に必要な「セッションの開始・終了」「パスワードのハッシュ化」「アクセス制限」といった機能をメソッドとして提供します。ビューやコントローラを自動生成しない点が特徴で、ログイン画面や遷移は開発者が自分で書きます。そのぶん生成物が少なく、アプリの挙動を把握しやすいのが利点です。パスワードのハッシュ化にはbcryptを使います。
DeviseとSorceryの違い
Railsの認証gemはDeviseが定番ですが、両者は設計思想が逆です。判断材料として主な違いを整理します。
| 観点 | Sorcery | Devise |
|---|---|---|
| 提供範囲 | 認証メソッドのみ | 画面・ルーティングまで一式 |
| ビュー生成 | なし(自作) | あり(自動生成) |
| 学習コスト | 低め(構造が単純) | 高め(規約が多い) |
| カスタマイズ | コードを直接記述 | 設定・オーバーライド中心 |
| 向くケース | 認証を自分で制御したい中小規模 | 標準機能を素早く揃えたい |
Deviseは規約に沿えば短時間で認証一式が整いますが、標準から外れた要件では設定の把握に時間がかかります。Sorceryは書く量こそ増えますが、どこで何が起きているかがコード上に見えます。
Sorceryを避けるべきケース
認証まわりを「なるべく書かずに済ませたい」プロジェクトにSorceryは向きません。管理画面の即席構築、二要素認証やアカウント管理UIを標準で揃えたい場合は、画面まで生成するDeviseのほうが総工数は小さくなります。Sorceryが生きるのは、ログイン画面のデザインや遷移を自前で作り込みたい、余計な依存を増やしたくない、という要件が明確なときです。
Sorceryのインストールと初期設定
導入は4ステップで完了します。まずGemfileに追記します。バージョンを固定しておくと、後日のbundle updateで意図せず更新されるのを防げます。
gem 'sorcery', '~> 0.18.0'
bundle installの後、インストールジェネレータを実行します。rails generateジェネレータの使い方と同じ流れで、設定ファイルとマイグレーションが生成されます。
rails g sorcery:install
rails db:migrate
これで初期化ファイルconfig/initializers/sorcery.rb、Userモデル、usersテーブル(crypted_password・saltカラムを含む)が作られます。生成されたUserモデルにはauthenticates_with_sorcery!が入っており、これが認証の起点です。バリデーションは自動では付かないため、メールとパスワードの検証は自分で追加します。
class User < ApplicationRecord
authenticates_with_sorcery!
validates :email, presence: true, uniqueness: true,
format: { with: URI::MailTo::EMAIL_REGEXP }
validates :password, length: { minimum: 8 }, if: -> { new_record? || changes[:crypted_password] }
validates :password, confirmation: true, if: -> { new_record? || changes[:crypted_password] }
validates :password_confirmation, presence: true, if: -> { new_record? || changes[:crypted_password] }
end
パスワードは平文カラムを持たず、代入時に自動でハッシュ化されてcrypted_passwordへ保存されます。そのためバリデーションは「新規作成時か、パスワード変更時のみ」に限定するのが定石です。
ログイン・ログアウトの実装
Sorceryは画面を生成しないので、ルーティングとコントローラを自分で用意します。まずconfig/routes.rbにセッション用のルートを追加します。
resources :user_sessions, only: [:new, :create, :destroy]
get 'login', to: 'user_sessions#new'
delete 'logout', to: 'user_sessions#destroy'
コントローラでは、Sorceryのloginで認証し、logoutでセッションを破棄します。loginは成功時にユーザーオブジェクト、失敗時にnilを返すので、その真偽で分岐します。
class UserSessionsController < ApplicationController
def new
end
def create
if login(params[:email], params[:password])
redirect_back_or_to(root_path, notice: 'ログインしました')
else
flash.now[:alert] = 'メールアドレスかパスワードが違います'
render :new, status: :unprocessable_entity
end
end
def destroy
logout
redirect_to root_path, notice: 'ログアウトしました'
end
end
ログインフォームはform_withでlogin_path宛てに作り、emailとpasswordを送信します。認証に失敗したフォーム再描画では、Rails 7以降の作法にあわせてstatus: :unprocessable_entityを返しておくと、Turboでも正しく再表示されます。
Sorceryの主要ヘルパーメソッド
認証状態の判定やアクセス制限は、Sorceryが提供するヘルパーメソッドで行います。GSCでもnot_authenticatedやredirect_back_or_to単体で検索されており、役割を押さえておくと実装が速くなります。
| メソッド | 役割 |
|---|---|
login(email, password) |
認証してセッション開始。失敗時はnil |
logout |
セッションを破棄 |
logged_in? |
ログイン中かを真偽で返す |
current_user |
ログイン中のユーザーを返す |
require_login |
未ログインを弾くbefore_action用 |
not_authenticated |
未認証時に呼ばれる。上書きで遷移先を制御 |
redirect_back_or_to(path) |
元のページ、なければpathへ戻す |
アクセス制限はrequire_loginをbefore_actionに指定し、未認証時の挙動はnot_authenticatedを上書きして決めます。両者はApplicationControllerに置くのが基本です。
class ApplicationController < ActionController::Base
before_action :require_login
private
def not_authenticated
redirect_to login_path, alert: 'ログインが必要です'
end
end
公開ページを持つコントローラではskip_before_action :require_login, only: [:index, :show]のように除外します。ログイン後に元のページへ戻すには、認証成功時にredirect_back_or_toを使います。
submoduleで機能を追加する
パスワードリセットやアカウントロックといった追加機能は、Sorceryのsubmoduleとして個別に有効化します。必要なものだけ足す設計なので、使わない機能のコードは入りません。ジェネレータがマイグレーションと設定を生成します。有効化するsubmoduleは初期化ファイルでRails.application.config.sorcery.submodules = [...]にまとめて列挙します。複数使う場合も1つの配列にまとめること(別々に代入すると後の宣言が前を上書きし、片方しか効きません)。
パスワードリセット
rails g sorcery:install reset_password --only-submodulesを実行し、リセットトークンのカラムを追加します。設定ファイルでメール送信クラスを指定すると、リセットリンク付きメールが送られます。
Rails.application.config.sorcery.configure do |config|
config.user_config do |user|
user.reset_password_mailer = UserMailer
end
end
アカウントロック(総当たり対策)
連続したログイン失敗でアカウントを一時ロックするには、brute_force_protection submoduleを追加します。失敗回数を数えるカラムが加わり、既定回数を超えるとロックされます。パスワード総当たり攻撃への基本的な防御になります。
rails g sorcery:install brute_force_protection --only-submodules
rails db:migrate
メール認証でアカウント有効化
登録直後のアカウントを「メール確認済みまで無効」にするには、user_activation submoduleを使います。登録時に確認メールを送り、リンクを踏むと有効化される流れです。捨てアドレスによる不正登録を減らせます。設定でメール送信クラスと、有効化前のログイン可否を指定します。
外部サービス連携(OAuth)でソーシャルログイン
Google・GitHub・LINEなどのアカウントでログインさせるには、:external submoduleを使います。ここで最も多いつまずきが、submodulesへの:external宣言忘れです。この宣言がないとexternal_providersを書いても機能しません。初期化ファイルの冒頭で必ず宣言します。
Rails.application.config.sorcery.submodules = [:external]
Rails.application.config.sorcery.configure do |config|
config.external_providers = [:google]
config.google.key = ENV['GOOGLE_KEY']
config.google.secret = ENV['GOOGLE_SECRET']
config.google.callback_url = 'http://localhost:3000/oauth/callback?provider=google'
config.google.user_info_mapping = { email: 'email', username: 'name' }
end
APIキーとシークレットはソースに直書きせず、環境変数で管理します。プロバイダごとにuser_info_mappingで取得情報とカラムを対応づけます。0.18.0が対応する外部プロバイダにはGoogle・GitHub・LINE・Slack・Facebookなどがあります。
なお、旧来よく例に挙がるTwitter(現X)連携は、X側のAPI仕様・料金体系が2023年以降に変わっており、無償のログイン用途では使いにくくなりました。新規実装ではGoogleやGitHub、国内向けならLINEを主軸に選ぶのが現実的です。トークンを使ったAPI側の認証を組みたい場合は、Rails APIのJWT認証と実装手順もあわせて検討してください。
セキュリティ対策とよくあるつまずき
認証はアプリの中核なので、Sorceryの機能に加えてRails側の基本対策を必ず併用します。押さえるべきは次の4点です。
- HTTPS強制:
config.force_ssl = trueで通信を暗号化し、パスワードやセッションの傍受を防ぐ。 - パスワードのハッシュ化:Sorceryが依存するbcryptで自動処理される。最小文字数はモデルのバリデーションで担保する。
- Strong Parameters:
params.require(:user).permit(...)で受け取る値を限定し、想定外カラムの更新を防ぐ。 - CSRF対策:Railsの既定保護を有効に保つ。外部認証のコールバックは検証対象を確認する。
実装でつまずいたときの切り分けは、症状ごとにほぼ決まっています。
| 症状 | 主な原因 |
|---|---|
| ログインが常に失敗する | authenticates_with_sorcery!漏れ/migration未実行 |
| 制限ページに素通りできる | require_loginのbefore_action未設定 |
| 外部認証が動かない | submodules = [:external]宣言漏れ/callback URL不一致 |
| bundle installで衝突 | Rails 7.1未満で利用(0.18.0は7.1以上が必要) |
認証が動かないときは、まずrails consoleでUser.firstを確認し、crypted_passwordが保存されているかを見ると原因を絞り込めます。Railsの開発環境そのものを見直す場合はVSCodeでのRails開発環境の構築も参考になります。
よくある質問
Sorceryとは何のgemですか?
Ruby on Railsに認証機能を組み込むための軽量gemです。ログイン・ログアウト・パスワード管理などの基本メソッドを提供し、画面や制御ロジックは開発者が自作します。英単語のsorcery(魔術)やゲームブックとは無関係です。
SorceryとDeviseはどちらを選ぶべきですか?
認証まわりを自分で制御したい、依存を増やしたくない中小規模ならSorcery、画面を含む標準機能を素早く揃えたいならDeviseが向きます。書く量はSorceryが多く、その代わり挙動が把握しやすくなります。
Sorceryの最新バージョンと対応Railsは?
最新は0.18.0(MITライセンス)で、railties 7.1以上、つまりRails 7.1以上に対応します。依存gemはbcrypt・oauth・oauth2です。導入前にプロジェクトのRailsバージョンを確認してください。
not_authenticatedメソッドは何をしますか?
未認証のユーザーがrequire_loginで保護されたページにアクセスしたときに呼ばれるメソッドです。既定ではルートパス(root_path)へリダイレクトしますが、コントローラで上書きしてログイン画面へ誘導するなど、遷移先を自由に決められます。
Googleログインが動かないときは何を確認しますか?
まず初期化ファイルでRails.application.config.sorcery.submodules = [:external]を宣言しているかを確認します。次にキー・シークレットの環境変数、コールバックURLがプロバイダ側の登録値と一致しているかを見ます。まずこの3点を確認すると、原因を絞り込めます。