管理者認証モジュール
概要説明
管理者認証モジュールは、管理ユーザーのアイデンティティ検証とセッション管理を行います。Firebase認証を使用してアプリケーションの管理セクションへの安全なアクセスを提供し、管理者ログインフローと、管理者がサポート目的でグループメンバーのアイデンティティを引き受けることができる特殊な代理ログイン機能を処理します。
アクティビティ図
---
config:
theme: base
layout: dagre
flowchart:
curve: linear
htmlLabels: true
themeVariables:
edgeLabelBackground: "transparent"
---
flowchart TB
%% Main components
Client[クライアントアプリケーション]
AuthController[認証コントローラー]
AuthService(認証サービス)
Firebase((Firebase認証))
UserDB[(ユーザー)]
RoleDB[(ロール)]
SessionDB[(Cookie)]
Client --- 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 --> AuthController
AuthController --- 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 --> AuthService
AuthService --- 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'>Firebaseトークン検証</p>
</div>
]
Step3 --> Firebase
Firebase --- 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 --> AuthService
AuthService --- 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 --> UserDB
AuthService --- Step6[
<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'>6</span>
<p style='margin-top: 8px'>管理者ロール確認</p>
</div>
]
Step6 --> RoleDB
AuthService --- 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'>認証Cookie作成</p>
</div>
]
Step7 --> SessionDB
AuthService --- Step8[
<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'>8</span>
<p style='margin-top: 8px'>認証Cookie生成</p>
</div>
]
Step8 --> AuthController
AuthController --- 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 --> Client
%% Styling
style Client fill:#e6f3ff,stroke:#0066cc,stroke-width:2px
style AuthController fill:#e6f3ff,stroke:#0066cc,stroke-width:2px
style AuthService fill:#f0f8e6,stroke:#339933,stroke-width:2px
style Firebase fill:#fcd9d9,stroke:#cc3333,stroke-width:2px
style UserDB fill:#ffe6cc,stroke:#ff9900,stroke-width:2px
style RoleDB fill:#ffe6cc,stroke:#ff9900,stroke-width:2px
style SessionDB 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 Step6 fill:transparent,stroke:transparent,stroke-width:1px
style Step7 fill:transparent,stroke:transparent,stroke-width:1px
style Step8 fill:transparent,stroke:transparent,stroke-width:1px
style Step9 fill:transparent,stroke:transparent,stroke-width:1px
API: 管理者認証API
ケースドキュメント
ケース1: 管理者ログイン
説明
管理者が有効な認証情報と適切なロールで正常にログインします。
シーケンス図
sequenceDiagram
participant Admin as 管理者
participant API as 認証コントローラー
participant Service as 認証サービス
participant Firebase
participant UserDB as users
participant AdminRoleDB as admin_roles
participant AdminRoleUserDB as admin_role_user
participant GroupDB as groups
participant GroupMemberDB as group_members
participant GroupRoleDB as group_roles
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,UserDB: ステップ4: ユーザー検索
Service->>UserDB: findByUid(uid)
UserDB-->>Service: ユーザーデータの返却
Note over Service,AdminRoleUserDB: ステップ5: 管理者ロール確認
Service->>AdminRoleUserDB: 管理者ロールの確認
AdminRoleUserDB-->>Service: ロールデータの返却
Note over Service,GroupDB: ステップ6: グループデータ読込
Service->>GroupDB: グループデータの読込
GroupDB-->>Service: グループデータの返却
Note over Service,GroupMemberDB: ステップ7: グループメンバー読込
Service->>GroupMemberDB: グループメンバーの読込
GroupMemberDB-->>Service: グループメンバーデータの返却
Note over Service,GroupRoleDB: ステップ8: グループロール読込
Service->>GroupRoleDB: グループロールの読込
GroupRoleDB-->>Service: グループロールデータの返却
Note over Service,API: ステップ9: 認証Cookie生成
Service->>Service: createAuthCookie(user)
Note over API,Admin: ステップ10: レスポンス返却
API-->>Admin: 200 OK (ユーザーデータとCookie)
ステップ
ステップ1: ログイン送信
- 説明: 管理者がログイン認証情報を送信
- リクエスト:
POST /api/v1/admin/auth/login - ヘッダー:
- firebase-token: Firebase認証からのトークン
- 検証:
- トークン存在チェック
- トークンフォーマット検証
- レート制限チェック (5回/分)
ステップ2: ログイン処理
- 説明: コントローラーがリクエストを検証しサービスに渡す
- アクション:
- ヘッダーからトークンを抽出
- 認証サービスにログイン処理を呼び出し
- ログイン試行を記録
ステップ3: トークン検証
- 説明: Firebaseトークンの信頼性を検証
- アクション:
- 検証のためトークンをFirebaseに送信
- 検証済みトークンからユーザー情報を抽出
- 認証プロバイダーを確認
ステップ4: ユーザー検索
- 説明: データベースでユーザーレコードを検索
- アクション:
- Firebase UIDに一致するユーザーをデータベースに問い合わせ
- ユーザーが存在し、アクティブであることを確認
- ユーザーのリレーションをロード
ステップ5: 管理者ロール確認
- 説明: ユーザーが管理者権限を持っているか確認
- アクション:
- ユーザーのロール割り当てを確認
- 管理者ロールが存在することを確認
- ロール権限を検証
ステップ6: グループデータ読込
- 説明: グループ関連データの取得
- アクション:
- グループデータをデータベースに問い合わせ
- グループの存在を確認
- グループのリレーションをロード
ステップ7: グループメンバー読込
- 説明: グループメンバーデータの取得
- アクション:
- グループメンバーデータをデータベースに問い合わせ
- グループメンバーの存在を確認
- グループメンバーのリレーションをロード
ステップ8: グループロール読込
- 説明: グループロールデータの取得
- アクション:
- グループロールデータをデータベースに問い合わせ
- グループロールの存在を確認
- グループロールのリレーションをロード
ステップ9: 認証Cookie生成
- 説明: 安全なセッションCookieの作成
- アクション:
- 認証トークンの生成
- トークンを使用したCookieの作成
- secureとhttpOnlyフラグを設定
- 適切なドメインとパスを設定
ステップ10: レスポンス返却
- 説明: クライアントに成功レスポンスを送信
- レスポンス:
- 成功:
200 OK(ユーザーデータ付き) - レスポンスにCookieを設定
- レスポンス本文にユーザー詳細を含める
- 成功:
関連するデータベーステーブルとフィールド
erDiagram
users {
bigint id PK
string name "ユーザーのフルネーム"
string email "ユーザーのメールアドレス (ユニーク)"
string uid "Firebase ユーザーID (ユニーク)"
int status "アカウントステータス: 1: active, ): inactive"
boolean is_first_login "ユーザーが初回ログインを完了したかのフラグ"
timestamp created_at
timestamp updated_at
}
roles {
bigint id PK
string name "ロール表示名"
string slug "権限用ロール識別子 (ユニーク)"
timestamp created_at
timestamp updated_at
}
admin_role_user {
bigint user_id FK "usersテーブルへの参照"
bigint role_id FK "rolesテーブルへの参照"
timestamp created_at
timestamp updated_at
}
users ||--o{ admin_role_user : has
roles ||--o{ admin_role_user : has
エラー処理
-
ログ
- ログイン失敗はアプリケーションログに記録
- ロール検証エラーを記録
- (オプション) セキュリティイベントのSlackメッセージ送信
-
エラー詳細:
ステータスコード エラーメッセージ 説明 401 "ログイン情報が正しくありません。" 認証情報が無効な場合 403 "管理者権限がありません。" ユーザーに管理者ロールがない場合 429 "リクエストが多すぎます。" レート制限を超えた場合 401 例外メッセージを含む一般的なエラー 予期しないエラーが発生した場合
ケース2: 代理ログイン
説明
管理者がグループメンバーの代理としてログインします。
シーケンス図
sequenceDiagram
participant Admin as 管理者
participant API as 代理コントローラー
participant Service as 認証サービス
participant UserDB as データベース
participant SessionDB as データベース
Admin->>API: PATCH /api/v1/admin/auth/representative/{id}
API->>Service: loginAsRepresentative(user_id)
Service->>UserDB: findUserWithGroup(user_id)
UserDB-->>Service: ユーザーデータの返却
Service->>SessionDB: createRepresentativeSession(admin_id, user_id)
SessionDB-->>Service: セッションデータの返却
Service->>Service: generateRepresentativeCookie
API-->>Admin: 200 OK (Cookie付き)
ステップ
ステップ1: 代理リクエスト送信
- 説明: 管理者が代理としての操作をリクエスト
- リクエスト:
PATCH /api/v1/admin/auth/representative/{id} - ボディパラメータ:
- user_id: 代理するユーザーのID
- 検証:
- 管理者認証チェック
- ユーザー存在確認
- グループメンバーシップ検証
ステップ2: 代理ログイン処理
- 説明: 代理セッションの作成
- アクション:
- 管理者権限の確認
- ユーザーのグループメンバーシップの確認
- 代理コンテキストの作成
ステップ3: 代理セッション作成
- 説明: 代理セッションデータの保存
- アクション:
- セッション識別子の生成
- 管理者とユーザーレコードのリンク
- セッション有効期限の設定
- 代理アクセスのログ記録
ステップ4: Cookie生成
- 説明: 代理セッションCookieの作成
- アクション:
- 代理トークンの生成
- 安全なCookieの作成
- 適切なフラグと有効期限の設定
ステップ5: レスポンス返却
- 説明: 成功レスポンスの送信
- レスポンス:
- 成功:
200 OK(ユーザーデータ付き) - 代理Cookieの設定
- ユーザー詳細の含め
- 成功:
追加事項
- レート制限: 管理者ログイン試行はIPアドレスごとに1分間で5回に制限
- セッション有効期限: 管理者セッションは8時間の非アクティブ後に期限切れ
- 代理セッションは1時間後に期限切れ
- システムは全ての管理者および代理アクションの監査ログを維持
- 実装を検討すべき項目:
- 管理者アクセス用の二要素認証
- IPベースのアクセス制限
- アクティビティ監視とアラート
- セッションアクティビティ追跡
モジュール機能
| 名前 | 概要リンク | 説明 |
|---|---|---|
| 管理者ログイン | 管理者ログイン | ロール検証を伴う管理ユーザーの認証 |
| 代理ログイン | 代理ログイン | グループメンバーの代わりに行動するための認証 |
| 管理者ログアウト | 管理者ログアウト | 管理セッションの終了 |
| パスワード管理 | パスワード管理 | 管理者パスワードリセット機能 |