Deviseがやっていること ‐ Rails認証gem解説 - nyg1971/business_api GitHub Wiki
Deviseがやっていること - Rails認証gem解説
📋 概要
Deviseは Rails の認証システムを簡単に構築できる定番gemです。今回のJWT認証システムでも基盤部分として活用しています。
🔐 Deviseの主要機能
1. パスワード暗号化・検証
# 1. パスワード暗号化・検証
user.valid_password?('password123') # ← bcryptでハッシュ化して比較
# 2. ユーザー認証のヘルパーメソッド
user.authenticate('password123')
# 内部では bcrypt を使用してパスワードをハッシュ化
# 平文パスワードは保存せず、ハッシュ値のみDB保存
2. バリデーション自動追加
# Deviseが自動で追加するバリデーション
validates :email, presence: true, uniqueness: true
validates :password, length: { minimum: 6 }
# メール形式のバリデーション
validates :email, format: { with: /\A[^@\s]+@[^@\s]+\z/ }
# パスワード確認(password_confirmation)のバリデーション
validates :password_confirmation, presence: true, if: :password_required?
3. データベースカラム自動追加
# Deviseが自動生成するマイグレーション
class DeviseCreateUsers < ActiveRecord::Migration[7.0]
def change
create_table :users do |t|
## Database authenticatable
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
## Recoverable(パスワードリセット機能)
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable(ログイン記憶機能)
t.datetime :remember_created_at
## Trackable(ログイン追跡機能)
t.integer :sign_in_count, default: 0, null: false
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string :current_sign_in_ip
t.string :last_sign_in_ip
## Confirmable(メール確認機能)
t.string :confirmation_token
t.datetime :confirmed_at
t.datetime :confirmation_sent_at
t.string :unconfirmed_email
## Lockable(アカウントロック機能)
t.integer :failed_attempts, default: 0, null: false
t.string :unlock_token
t.datetime :locked_at
t.timestamps null: false
end
add_index :users, :email, unique: true
add_index :users, :reset_password_token, unique: true
add_index :users, :confirmation_token, unique: true
add_index :users, :unlock_token, unique: true
end
end
4. ルーティング自動生成(今回は使用していない)
# config/routes.rb で devise_for を使用した場合
devise_for :users
# 以下のルートが自動生成される
# Prefix Verb URI Pattern Controller#Action
# new_user_session GET /users/sign_in devise/sessions#new
# user_session POST /users/sign_in devise/sessions#create
# destroy_user_session DELETE /users/sign_out devise/sessions#destroy
# new_user_registration GET /users/sign_up devise/registrations#new
# user_registration POST /users devise/registrations#create
# edit_user_registration GET /users/edit devise/registrations#edit
# user_registration PATCH /users devise/registrations#update
# new_user_password GET /users/password/new devise/passwords#new
# edit_user_password GET /users/password/edit devise/passwords#edit
# user_password PATCH /users/password devise/passwords#update
# POST /users/password devise/passwords#create
🛠️ 今回のプロジェクトでのDeviseの使用方法
User モデルでの設定
# app/models/user.rb
class User < ApplicationRecord
# Devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
# 役職管理(独自拡張)
enum role: {
staff: 0,
manager: 1,
admin: 2
}
validates :role, presence: true
after_initialize :set_default_role, if: :new_record?
private
def set_default_role
self.role ||= :staff
end
end
使用しているDeviseモジュール
:database_authenticatable
1. # パスワード認証機能
user = User.find_by(email: "[email protected]")
user.valid_password?("password123") # => true/false
# 内部でbcryptを使用してパスワード検証
BCrypt::Password.new(user.encrypted_password) == "password123"
:registerable
2. # ユーザー登録機能
# Strong Parametersと組み合わせて使用
def user_params
params.require(:user).permit(:email, :password, :password_confirmation, :role)
end
user = User.new(user_params)
user.save # Deviseのバリデーションが自動適用
:recoverable
3. # パスワードリセット機能(今回未使用だが利用可能)
user.send_reset_password_instructions
# reset_password_token が生成され、メールが送信される
:rememberable
4. # "ログインを記憶する" 機能(今回未使用だが利用可能)
user.remember_me!
# remember_created_at が更新される
:validatable
5. # 自動バリデーション
# - email presence & uniqueness & format
# - password minimum length (6文字以上)
# - password_confirmation matching
🎯 JWT認証での活用パターン
API Controller での使用例
class Api::V1::AuthController < Api::V1::BaseController
def login
# emailでユーザーを検索
user = User.find_by(email: params[:email])
# Deviseの valid_password? メソッドを使用
if user&.valid_password?(params[:password])
# 認証成功:JWTトークンを生成
token = JsonWebToken.encode(user_id: user.id)
render json: {
token: token,
user: user.as_json(only: [:id, :email, :role]),
expires_at: 24.hours.from_now
}, status: :ok
else
# 認証失敗:Deviseが提供するセキュアなエラーハンドリング
render json: { error: 'Invalid credentials' }, status: :unauthorized
end
end
def signup
# Deviseの機能を活用したユーザー作成
user = User.new(user_params)
if user.save # Deviseのバリデーションが自動実行
# 登録成功:即座にJWTトークンを発行
token = JsonWebToken.encode(user_id: user.id)
render json: {
token: token,
user: user.as_json(only: [:id, :email, :role]),
expires_at: 24.hours.from_now
}, status: :created
else
# 登録失敗:Deviseのバリデーションエラーを返却
render json: {
errors: user.errors.full_messages
}, status: :unprocessable_entity
end
end
private
def user_params
params.require(:user).permit(:email, :password, :password_confirmation, :role)
end
end
🔒 セキュリティ機能
1. パスワードハッシュ化
# 入力されたパスワード
password = "my_secret_password"
# Deviseが自動で行うハッシュ化(bcrypt使用)
encrypted = BCrypt::Password.create(password)
# => "$2a$12$XYZ..." (60文字のハッシュ値)
# データベースには暗号化されたパスワードのみ保存
# 平文パスワードは保存されない
2. ブルートフォース攻撃対策
# Deviseの設定(config/initializers/devise.rb)
Devise.setup do |config|
# パスワード最小長
config.password_length = 6..128
# メール形式チェック
config.email_regexp = /\A[^@\s]+@[^@\s]+\z/
# ケースセンシティブ(大文字小文字区別)
config.case_insensitive_keys = [:email]
# ホワイトスペース除去
config.strip_whitespace_keys = [:email]
end
3. セッション管理(今回はJWTで代替)
# 通常のDevise使用時
class ApplicationController < ActionController::Base
before_action :authenticate_user! # Deviseの認証チェック
# Deviseが提供するヘルパーメソッド
def current_user
# セッションベースのユーザー取得
end
def user_signed_in?
# ログイン状態チェック
end
end
🎨 カスタマイズ例
1. 独自バリデーション追加
class User < ApplicationRecord
devise :database_authenticatable, :registerable, :validatable
# Deviseのバリデーションに加えて独自バリデーション
validates :role, presence: true
validates :email, format: {
with: /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i,
message: "企業メールアドレスを使用してください"
}
# パスワード強度チェック
validate :password_complexity
private
def password_complexity
return if password.blank?
unless password.match(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/)
errors.add :password, "大文字・小文字・数字を含む必要があります"
end
end
end
2. カスタムメソッド追加
class User < ApplicationRecord
devise :database_authenticatable, :registerable, :validatable
# 権限チェックメソッド
def can_access_admin_panel?
admin? || manager?
end
# ログイン試行回数制限
def increment_failed_attempts
self.failed_attempts ||= 0
self.failed_attempts += 1
if failed_attempts >= 5
self.locked_at = Time.current
end
save
end
# アカウントロック状態チェック
def access_locked?
locked_at.present? && locked_at > 30.minutes.ago
end
end
💡 学習・習得のポイント
Deviseの理解度
- Deviseの各モジュールの機能と使い分けの理解
- JWT認証との組み合わせによる柔軟な認証システムの構築
- セキュリティ要件に応じたDevise設定のカスタマイズ
実装スキル
- API認証でのDevise活用パターンの習得
- 既存Deviseアプリへの機能追加・カスタマイズ
- パスワードセキュリティとバリデーション設計の理解
実務への応用
- レガシーなセッション認証からJWT認証への移行設計
- エンタープライズレベルの認証要件への対応
- セキュリティインシデント防止のための実装パターン
Deviseは「認証の車輪の再発明」を防ぎ、セキュアで実用的な認証システムを素早く構築できる優れたgemです。JWT認証と組み合わせることで、モダンなAPI開発とレガシー支援の両方に対応できる柔軟な認証基盤を構築できます。