管理者ログイン
概要説明
管理者ログイン機能は、特に昇格された権限を持つ管理ユーザー向けの認証を提供します。標準的なユーザーログインと類似のフローですが、管理者ロールの検証と拡張されたユーザー読み込みの追加チェックが含まれています。この機能により、適切な管理者権限を持つユーザーのみがアプリケーションの管理セクションにアクセスできるようになり、通常のユーザーアクセスと管理機能の間に明確な分離が作られます。
アクティビティ図
---
config:
theme: base
layout: dagre
flowchart:
curve: linear
htmlLabels: true
themeVariables:
edgeLabelBackground: "transparent"
---
flowchart TD
%% Main components
AdminUser[管理者ユーザー]
FirebaseService[Firebase認証]
Database[(データベース)]
%% Process steps with numbering
AdminUser --- Step1[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>1</span>
<p style='margin-top: 8px'>ログイン送信</p>
</div>
]
Step1 --> ValidateRequest[リクエスト検証]
ValidateRequest --- Step2[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>2</span>
<p style='margin-top: 8px'>トークン抽出</p>
</div>
]
Step2 --> ExtractToken[Firebaseトークン抽出]
ExtractToken --- Step3[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>3</span>
<p style='margin-top: 8px'>認証サービスに送信</p>
</div>
]
Step3 --> AuthService[認証サービス]
AuthService --- Step4[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>4</span>
<p style='margin-top: 8px'>トークン検証</p>
</div>
]
Step4 --> FirebaseService
FirebaseService --- Step5[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>5</span>
<p style='margin-top: 8px'>トークン検証</p>
</div>
]
Step5 --> TokenCheck{有効なトークン?}
TokenCheck --- Step6A[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #cc6666 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>6A</span>
<p style='margin-top: 8px'>エラー返却</p>
</div>
]
Step6A -->|いいえ| ReturnError[エラー返却]
TokenCheck --- Step6B[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>6B</span>
<p style='margin-top: 8px'>ユーザー検索</p>
</div>
]
Step6B -->|はい| FindUser[データベースでユーザー検索]
FindUser --- Step7[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>7</span>
<p style='margin-top: 8px'>存在確認</p>
</div>
]
Step7 --> UserCheck{ユーザー存在?}
UserCheck --- Step8A[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #cc6666 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>8A</span>
<p style='margin-top: 8px'>エラー返却</p>
</div>
]
Step8A -->|いいえ| ReturnError
UserCheck --- Step8B[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>8B</span>
<p style='margin-top: 8px'>ロール確認</p>
</div>
]
Step8B -->|はい| CheckAdminRole[管理者ロール確認]
CheckAdminRole --- Step9[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>9</span>
<p style='margin-top: 8px'>ロール検証</p>
</div>
]
Step9 --> RoleCheck{管理者ロールあり?}
RoleCheck --- Step10A[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #cc6666 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>10A</span>
<p style='margin-top: 8px'>エラー返却</p>
</div>
]
Step10A -->|いいえ| ReturnError
RoleCheck --- Step10B[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #99cc66 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>10B</span>
<p style='margin-top: 8px'>Cookie生成</p>
</div>
]
Step10B -->|はい| GenerateCookies[認証Cookie生成]
GenerateCookies --- Step11[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #99cc66 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>11</span>
<p style='margin-top: 8px'>データ返却</p>
</div>
]
Step11 --> ReturnUserData[管理者ユーザーデータ返却]
ReturnUserData --- Step12[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #99cc66 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>12</span>
<p style='margin-top: 8px'>ログイン完了</p>
</div>
]
Step12 --> AdminUser
%% Styling
style AdminUser fill:#e6f3ff,stroke:#0066cc,stroke-width:2px
style ValidateRequest fill:#f0f8e6,stroke:#339933,stroke-width:2px
style ExtractToken fill:#f0f8e6,stroke:#339933,stroke-width:2px
style AuthService fill:#f0f8e6,stroke:#339933,stroke-width:2px
style FirebaseService fill:#fcd9d9,stroke:#cc3333,stroke-width:2px
style TokenCheck fill:#f5f0ff,stroke:#9966cc,stroke-width:2px
style FindUser fill:#f0f8e6,stroke:#339933,stroke-width:2px
style UserCheck fill:#f5f0ff,stroke:#9966cc,stroke-width:2px
style CheckAdminRole fill:#f0f8e6,stroke:#339933,stroke-width:2px
style RoleCheck fill:#f5f0ff,stroke:#9966cc,stroke-width:2px
style GenerateCookies fill:#f0f8e6,stroke:#339933,stroke-width:2px
style ReturnUserData fill:#f0f8e6,stroke:#339933,stroke-width:2px
style ReturnError fill:#fcd9d9,stroke:#cc3333,stroke-width:2px
style Database fill:#ffe6cc,stroke:#ff9900,stroke-width:2px
style Step1 fill:transparent,stroke:transparent,stroke-width:1px
style Step2 fill:transparent,stroke:transparent,stroke-width:1px
style Step3 fill:transparent,stroke:transparent,stroke-width:1px
style Step4 fill:transparent,stroke:transparent,stroke-width:1px
style Step5 fill:transparent,stroke:transparent,stroke-width:1px
style Step6A fill:transparent,stroke:transparent,stroke-width:1px
style Step6B fill:transparent,stroke:transparent,stroke-width:1px
style Step7 fill:transparent,stroke:transparent,stroke-width:1px
style Step8A fill:transparent,stroke:transparent,stroke-width:1px
style Step8B fill:transparent,stroke:transparent,stroke-width:1px
style Step9 fill:transparent,stroke:transparent,stroke-width:1px
style Step10A fill:transparent,stroke:transparent,stroke-width:1px
style Step10B fill:transparent,stroke:transparent,stroke-width:1px
style Step11 fill:transparent,stroke:transparent,stroke-width:1px
style Step12 fill:transparent,stroke:transparent,stroke-width:1px
API: 管理者ログインAPI
ケースドキュメント
ケース1: 管理者ログイン成功
説明
管理者が有効な認証情報と管理者ロールで正常にログインします。
シーケンス図
sequenceDiagram
participant Admin as 管理者
participant API as ログインコントローラー
participant Service as 認証サービス
participant Firebase
participant DB as データベース
Note over Admin,API: ステップ1: ログイン送信
Admin->>API: POST /api/v1/admin/auth/login (firebase-tokenあり)
Note over API,Service: ステップ2: ログイン処理
API->>Service: login(token, data)
Note over Service,Firebase: ステップ3: トークン検証
Service->>Firebase: verifyIdToken(token)
Firebase-->>Service: 検証済みユーザー情報の返却
Note over Service,DB: ステップ4: ユーザー検索
Service->>DB: findByUid(uid)
DB-->>Service: ユーザーデータの返却
Note over Service,DB: ステップ5: 管理者ロール確認
Service->>DB: 管理者ロールの確認
DB-->>Service: ロールデータの返却
Note over Service,DB: ステップ6: グループデータ読込
Service->>DB: グループデータの読込
DB-->>Service: グループデータの返却
Note over Service,DB: ステップ7: グループメンバー読込
Service->>DB: グループメンバーの読込
DB-->>Service: グループメンバーデータの返却
Note over Service,DB: ステップ8: グループロール読込
Service->>DB: グループロールの読込
DB-->>Service: グループロールデータの返却
Note over Service,API: ステップ9: 認証Cookie生成
Service->>Service: createAuthCookie(user)
Note over API,Admin: ステップ10: レスポンス返却
API-->>Admin: 200 OK (ユーザーデータとCookie)
ステップ
ステップ1: ログインリクエスト送信
- 説明: 管理者がFirebaseトークン付きでログインリクエストを送信
- リクエスト:
POST /api/v1/admin/auth/login - ヘッダー:
- firebase-token: Firebase認証トークン
- 検証:
- トークン存在チェック
- トークンフォーマット検証
ステップ2: ログイン処理
- 説明: コントローラーがリクエストを検証しサービスに渡す
- アクション:
- ヘッダーからトークンを抽出
- 認証サービスを呼び出し
ステップ3: トークン検証
- 説明: Firebaseトークンの信頼性を検証
- アクション:
- 検証のためトークンをFirebaseに送信
- 検証済みトークンからユーザー識別子を抽出
ステップ4: ユーザー検索
- 説明: ユーザーレコードを検索し管理者権限を確認
- アクション:
- Firebase UIDに一致するユーザーをデータベースに問い合わせ
- ユーザーの管理者ロールリレーションをロード
- ユーザーに管理者ロールが割り当てられているか確認
ステップ5: 管理者ロール確認
- 説明: ユーザーが適切な管理者権限を持っていることを確認
- アクション:
- 管理者ロールが存在し有効であることを確認
- 特定のロール権限が必要かどうかを確認
ステップ6: グループデータ読込
- 説明: ユーザーに関連するグループデータを読み込む
- アクション:
- ユーザーのグループメンバーシップに関するグループデータベースを照会
- 各グループに関連するグループデータをロード
ステップ7: グループメンバー読込
- 説明: ユーザーに関連するグループメンバーデータを読み込む
- アクション:
- ユーザーのメンバーシップ詳細に関するグループメンバーデータベースを照会
- 各グループに関連するグループメンバーデータをロード
ステップ8: グループロール読込
- 説明: ユーザーに関連するグループロールデータを読み込む
- アクション:
- 各グループでのユーザーのロールに関するグループロールデータベースを照会
- 各グループに関連するグループロールデータをロード
ステップ9: 認証Cookie生成
- 説明: 安全な管理者セッションCookieを作成
- アクション:
- 認証トークンの生成
- トークンを使用したCookieの作成:
Trend-Viewer_auth_api_token - ログイン状態Cookieの作成:
Trend-Viewer_is_logged_in
ステップ10: レスポンス返却
- 説明: クライアントに成功レスポンスを送信
- レスポンス:
- 成功:
200 OK(管理者ユーザーデータ付き) - レスポンスにCookieを設定
- ロール情報を含むユーザー詳細を含める
- 成功:
関連するデータベーステーブルとフィールド
erDiagram
users {
id bigint "主キー"
name string "ユーザーのフルネーム"
email string "ユーザーのメールアドレス (ユニーク)"
uid string "Firebase UID"
status int "アカウントステータス"
is_first_login boolean "ユーザーが初回ログインを完了したかのフラグ"
payment_provider_customer_id string "決済プロバイダーの顧客ID"
show_free_plan_modal boolean "無料プランモーダル表示フラグ"
group_id bigint "groupsテーブルへの参照"
created_at timestamp "レコード作成タイムスタンプ"
updated_at timestamp "レコード最終更新タイムスタンプ"
}
groups {
id bigint "主キー"
name string "グループ名"
created_at timestamp "レコード作成タイムスタンプ"
updated_at timestamp "レコード最終更新タイムスタンプ"
}
group_members {
id bigint "主キー"
user_id bigint "usersテーブルへの参照"
group_id bigint "groupsテーブルへの参照"
group_role_id bigint "group_rolesテーブルへの参照"
created_at timestamp "レコード作成タイムスタンプ"
updated_at timestamp "レコード最終更新タイムスタンプ"
}
group_roles {
id bigint "主キー"
name string "ロール名"
slug string "ロールスラッグ"
created_at timestamp "レコード作成タイムスタンプ"
updated_at timestamp "レコード最終更新タイムスタンプ"
}
admin_roles {
id bigint "主キー"
name string "ロール名"
slug string "ロールスラッグ"
created_at timestamp "レコード作成タイムスタンプ"
updated_at timestamp "レコード最終更新タイムスタンプ"
}
admin_role_user {
user_id bigint "usersテーブルへの参照"
admin_role_id bigint "admin_rolesテーブルへの参照"
created_at timestamp "レコード作成タイムスタンプ"
updated_at timestamp "レコード最終更新タイムスタンプ"
}
users ||--o{ group_members : has
groups ||--o{ group_members : has
group_roles ||--o{ group_members : has
users ||--o{ admin_role_user : has
admin_roles ||--o{ admin_role_user : has
エラー処理
-
ログ
- ログイン失敗はアプリケーションログに記録
- ロール検証エラーを記録
- (オプション) セキュリティイベントのSlackメッセージ送信
-
エラー詳細:
ステータスコード エラーメッセージ 説明 401 "ログイン情報が正しくありません。" 管理者ロールにユーザーが見つからない場合 401 "認証情報と一致するレコードがありません。" ログインに失敗した場合 401 "問題が発生しました。申し訳ございませんが、もう一度お試しください。" 予期しないエラーが発生した場合
ケース2: 管理者ログイン失敗 (管理者ロールなし)
説明
有効な認証情報を持つユーザーがログインを試みるが、管理者ロールを持っていない。
シーケンス図
sequenceDiagram
participant User as ユーザー
participant API as 管理者ログインコントローラー
participant Service as 認証サービス
participant Firebase
participant DB as データベース
User->>API: POST /api/v1/admin/auth/login (firebase-tokenあり)
API->>Service: login(token, data)
Service->>Firebase: verifyIdToken(token)
Firebase-->>Service: 検証済みトークンデータの返却
Service->>DB: findByUid(firebase_uid)
DB-->>Service: ユーザーデータの返却
Service->>DB: 管理者ロール読込
DB-->>Service: 空のロール返却
Service-->>API: authInfoとユーザーを返却
API->>API: ユーザーが管理者ロールを持つか確認
API-->>User: 401 未認証 (管理者ロールなし)
ステップ
ステップ1: ログインリクエスト送信
- 説明: ユーザーが有効なFirebaseトークンでログインリクエストを送信
- リクエスト: 成功フローと同じ
ステップ2: トークン検証成功
- 説明: Firebaseがトークンを検証しユーザーが見つかる
- アクション: ロールチェックまで成功フローと同じ
ステップ3: 管理者ロールチェック失敗
- 説明: システムが管理者ロールを確認するが見つからない
- アクション:
- adminRoleリレーションをチェック
- ユーザーに必要な権限がないことを判断
ステップ4: エラーレスポンス
- 説明: ユーザーに適切なエラーを返す
- レスポンス: 権限に関するエラーメッセージ付きの
401 未認証
追加事項
- 管理者ログインは通常のユーザーログインと認証インフラを共有している
- 管理者ロールチェックは通常のログインには存在しない追加レイヤー
- ログイン後に利用可能な機能はロールベースのアクセス制御によって決定される
- 管理者ユーザーは異なる権限レベルを持つ複数のロールを持つことがある
- 管理者セッションは通常のユーザーセッションと同じセキュリティプロパティを持つ