認証まわり
WARNING
このページは旧 account.uzu-app.com + iframe / postMessage 方式の説明 (Studio や mdms.jp の旧実装) で、現在は 認証基盤 (auth platform) への移行が進行中です。新規サービスの認証は新基盤側を読んでください。
INFO
ここは Firebase Authentication 経由の ユーザー認証 の話。サーバー側の GCP リソース認証 (BigQuery / Cloud Storage / Firebase Admin / Play Store API 等) は GCP サービスアカウント認証 (WIF + ADC) を見る。
Firebase Authentication を使っている
- 環境(Project ID) は3つ存在する
- uzu-dev
- uzu-stg
- uzu-prd
- 各サービスで共通化している。
- studio
- analytics
- mdms.jp
- uzu-mobile
ユーザーには 「ウズアカウント」という見せ方をします。
アーキテクチャ
(dev./stg.)account.uzu-app.com がfirebase authentication と通信して、認証情報を保存する。(cookie 等はクロスドメインで参照できないので、accountサービス以外からは認証情報を参照できない。)
他のサービス、 analytics.uzu-app.com, mdms.jp は account.uzu-app.com と iframe, postMessage を通じて認証情報をやり取りする。
認証情報の例
- ログイン画面
- ログインしているか/していないかが変更されたら通知する (onAuthStateChangedのラップ)
- ログインしている場合はユーザー情報も渡すjson
{ uid: string; name?: string; iconUrl?: string; twitterUid?: string; }
- ログインしている場合はユーザー情報も渡す
- 認証トークンを渡す (getTokenのラップ)
Firebase Auth ユーザーは削除しない
uid は上記のとおり studio / analytics / mdms.jp / uzu-mobile で共有している。Firebase Auth のユーザーを消すと、UZU 以外のサービスに残っている User が uid の指す先を失い、ログインできなくなる。
そのためアプリ・backend のどの経路からも Firebase Auth ユーザーは削除しない。admin の deleteUser も UZU の DB からユーザーを消すだけで、Auth には触らない。
退会アカウントの物理削除
退会 (deactivationReasonUser) は論理削除で、users.deleted_at を立ててニックネームとアイコンを匿名化する。退会済みの認証情報でログインすると退会済み画面に着く。
同じ認証情報で登録し直したいユーザー向けに、退会済みアカウントを DB から物理削除する経路がある。
| API | 用途 |
|---|---|
canDeleteDeactivatedAccount(userId) (Query) | 退会済みアカウントを物理削除できるか |
deleteDeactivatedAccount(input: { userId }) (Mutation) | 退会済みアカウントを物理削除する |
deleteUser(input: { userId }) (Mutation) | admin が任意のユーザーを物理削除する |
前 2 つは AuthUser で本人確認を行う。admin token は AuthUser を通過するので、運営が退会済みユーザーの問い合わせに応じて代行実行できる。deleteUser は退会していないユーザーも対象にできる admin 専用の経路。
どれも usecase.HardDeleteUser を通る。削除するのは、そのユーザーしか参照しない付随データ (user_deactivation_reasons / notifications の受信分 / user_devices / user_locales / user_scenario_status / favorite_scenario_sets / chatroom_users / user_activity_profiles / favorite_reviews / spectator_mutes / spectators) だけ。
favorite_reviews は reviews.favorite_count に件数が非正規化されているため、行を消したあと同じトランザクション内で対象レビューの件数を数え直す。
users を参照する FK の大半は NO ACTION なので、上記に含まれないテーブルに 1 行でも残っていれば users の DELETE が制約違反で止まる。これは意図した設計で、「UZU で実際に遊んだ・課金した・作品を持っているアカウントは物理削除させない」という線を実装の条件分岐ではなく DB 構造で担保している。
user_relationships は削除対象に含めない。自分を消すために他ユーザーのフレンド一覧やブロックの意思表示を書き換えないため。退会の時点で FRIEND / REQUESTING は削除されるので、退会済みアカウントがこれで詰まることはほぼない。在籍中のユーザーを admin から物理削除したい場合は、先に退会を通してから実行する。
削除可否の判定はトランザクション内で実際に HardDeleteUser を実行して必ず rollback する dry-run で行う。判定専用のクエリを別に持つと、削除範囲や FK が変わったときに判定側だけ古くなって「削除できると言ったのに失敗する」ズレが生まれるため。
判定は読み取りに見えて実際には対象ユーザーの行に書き込みロックを取る。退会画面からしか呼ばれず頻度が低いので許容しているが、一覧表示など多重に叩く箇所からは使わないこと。
users の DELETE は users を参照する全 FK の整合性チェックを伴い、参照側カラムに索引が無いテーブルは 1 件も該当行が無いことを確かめるために全件走査される。dry-run と実削除で 2 回走るので、users を参照する FK を足すときは参照側カラムに索引を張ること。
ログインフローで退会済みか判定するユーザー取得 (UserDataInAuthenticationFlow) は GraphQL キャッシュを使わず毎回 backend に問い合わせる。物理削除も運営の退会取り消し (reactivateUser) もログアウト中に起きるうえ、mobile の GraphQL キャッシュは端末に永続化されていて再起動でも消えない。キャッシュを読むと削除・復元前の deletedAt で退会済み画面に戻され、再登録も復元後のログインもできなくなる。
認証トークンを取得するプロセス
以下の手順で、認証トークンは取得できます。
- mdms.jp から account.uzu-app.com に認証トークン取得リクエスト
REQUEST_TOKENを送る - account.uzu-app.com から firebase authentication の API
getTokenを呼び出す - account.uzu-app.com が 認証トークンを取得する
- account.uzu-app.com が mdms.jp に認証トークンを返却する
REQUEST_TOKEN_RESPONSE