ユーザーログイン

概要説明

ユーザーログイン機能により、登録済みユーザーはメールアドレスとFirebaseトークンを使用してシステムに認証できます。システムはFirebaseトークンを検証し、ユーザーのステータスとグループメンバーシップをチェックしてから、セッションを作成し、認証クッキーを返します。

アクティビティ図

flowchart TD
    A[クライアントがログインリクエストを送信] --> B[リクエストデータを検証]
    B --> C{データは有効?}
    C -->|いいえ| D[検証エラーを返す]
    C -->|はい| E[Firebaseトークンを検証]
    E --> F{トークンは有効?}
    F -->|いいえ| G[認証エラーを返す]
    F -->|はい| H[UIDでユーザーを検索]
    H --> I{ユーザーは存在?}
    I -->|いいえ| J[ユーザーが見つからないエラーを返す]
    I -->|はい| K[ユーザーステータスをチェック]
    K --> L{ユーザーはアクティブ?}
    L -->|いいえ| M[非アクティブユーザーエラーを返す]
    L -->|はい| N[グループメンバーシップをチェック]
    N --> O{ユーザーはグループに所属?}
    O -->|いいえ| P[グループなしエラーを返す]
    O -->|はい| Q[認証クッキーを作成]
    Q --> R[成功レスポンスを返す]
    
    style A fill:#e1f5fe
    style R fill:#c8e6c9
    style D fill:#ffcdd2
    style G fill:#ffcdd2
    style J fill:#ffcdd2
    style M fill:#ffcdd2
    style P fill:#ffcdd2

シーケンス図

ログイン成功

sequenceDiagram
    participant Client
    participant LoginController
    participant AuthService
    participant Firebase
    participant Database
    
    Client->>LoginController: POST /api/v1/general/auth/login
    Note over Client,LoginController: {email, firebase-token header}
    
    LoginController->>LoginController: リクエストを検証
    LoginController->>AuthService: login(email, firebaseToken)
    
    AuthService->>Firebase: verifyIdToken(firebaseToken)
    Firebase-->>AuthService: ユーザー情報 (uid, email)
    
    AuthService->>Database: UIDでユーザーを検索
    Database-->>AuthService: ユーザーデータ
    
    AuthService->>Database: ユーザーステータスとグループをチェック
    Database-->>AuthService: グループメンバーシップ情報
    
    AuthService->>AuthService: createAuthCookieByUser()
    AuthService-->>LoginController: ユーザーデータ + クッキー
    
    LoginController->>Client: 200 OK + Set-Cookie headers

ログイン失敗

sequenceDiagram
    participant Client
    participant LoginController
    participant AuthService
    participant Firebase
    
    Client->>LoginController: POST /api/v1/general/auth/login
    Note over Client,LoginController: 無効または期限切れのトークン
    
    LoginController->>LoginController: リクエストを検証
    LoginController->>AuthService: login(email, firebaseToken)
    
    AuthService->>Firebase: verifyIdToken(firebaseToken)
    Firebase-->>AuthService: 無効なトークンエラー
    
    AuthService-->>LoginController: 認証失敗
    
    LoginController->>Client: 401 Unauthorized

ステップ

ステップ1: リクエスト検証

入力:

  • リクエストボディからのメールアドレス
  • firebase-tokenヘッダーからのFirebaseトークン

ステップ2: Firebaseトークン検証

プロセス:

  • ヘッダーからFirebase IDトークンを抽出
  • Firebase認証サービスにトークンを送信
  • トークンの真正性と有効期限を検証
  • ユーザー情報を抽出 (UID, メール, プロバイダー)

ステップ3: ユーザー検索

取得されるユーザーデータ:

  • ユーザーID, 名前, メール, ステータス
  • グループメンバーシップ
  • サブスクリプション情報
  • アカウント作成日

ステップ4: ステータスチェック

ユーザーステータス検証:

  • usersテーブルのstatusフィールドをチェック
  • 有効なステータス: 1 (アクティブ), 0 (非アクティブ)
  • アカウント停止の追加チェック

ステップ5: グループメンバーシップ

要件:

  • ユーザーは少なくとも1つのアクティブなグループに所属している必要がある
  • グループはstatus = 1 (アクティブ) である必要がある
  • ユーザーは有効なロール割り当てが必要

ステップ6: セッション作成

保存されるセッションデータ:

  • ユーザーIDと認証トークン
  • IPアドレスとユーザーエージェント
  • ログインタイムスタンプ
  • セッション有効期限

ステップ7: レスポンス生成

HTTPヘッダー:

  • Set-Cookie: auth_token=...; HttpOnly; Secure; SameSite=Lax
  • Set-Cookie: logged_in=true; HttpOnly; Secure; SameSite=Lax
  • Content-Type: application/json

エラー処理サマリー

ステップ エラーコード HTTPステータス 説明
1 VALIDATION_ERROR 400 無効なメールまたはトークン不足
2 UNAUTHORIZED 401 無効/期限切れのFirebaseトークン
3 USER_NOT_FOUND 404 データベースにユーザーが存在しない
4 USER_INACTIVE 403 ユーザーアカウントが無効化されている
5 NO_GROUP_MEMBERSHIP 403 ユーザーがどのグループにも割り当てられていない
6-7 INTERNAL_SERVER_ERROR 500 セッション作成中のサーバーエラー

パフォーマンス考慮事項

  • データベースインデックス: uid, email, statusフィールドのインデックス
  • キャッシュ: グループとサブスクリプションデータを5分間キャッシュ
  • コネクションプーリング: データベース接続を効率的に再利用
  • 非同期操作: Firebase検証をユーザー検索と並行して実行
  • レート制限: ブルートフォース攻撃を防止 (IPあたり5回/分)

詳細なCookie

認証Cookie

1. 認証APIトークンCookie

Set-Cookie: Trend-Viewer_auth_api_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...; 
HttpOnly; 
Secure; 
SameSite=Lax; 

プロパティ:

  • Name: Trend-Viewer_auth_api_token ({app_name}は設定からのアプリケーション名)
  • Value: エンコードされたJWTトークン
  • HttpOnly: true (JavaScriptからアクセス不可)
  • Secure: true (HTTPS経由でのみ送信)
  • SameSite: Lax (CSRF保護)

2. ログイン状態Cookie

Set-Cookie: Trend-Viewer_is_logged_in=true; 
HttpOnly; 
Secure; 
SameSite=Lax; 

プロパティ:

  • Name: Trend-Viewer_is_logged_in
  • Value: true
  • HttpOnly: true
  • Secure: `true**
  • SameSite: Lax