この記事は個人の見解であり、所属する組織の公式見解ではありません。
辛い思い出ありますので言えますが、ユーザー認証はクライアント側のパスワード保存に依存してはいけません ^^; 通常認証に使わなくても、IDFVとかのバックアップ用端末->アカウント紐付き情報を取ってね。
数千人、数万人のクライアント側パスワード情報がバグによって同時に消えることありますので^^
ゲーム滅亡を避けましょう^^
実際にあった話
うちのチームのローンチ時に起きました。
数千人のクライアント側パスワード情報が同時に消されました。
IDFV情報を持っていたおかげでユーザーログインに影響なかったですが、その情報がなかったら数千人がCSに連絡するor二度とプレイできません。ゲームの規模がより大きくて数万人、数十万人の被害者が出た場合、地獄を想像します ^^;
##滅亡の作り方
名前/PWがないとユーザー認証できない仕組み
クライアント端末とサーバーアカウントを紐づけるのは、クライアント側のキーチェインに保存するユーザー名とパスワード。のみ。IDFVとははサーバーが保存しません。
//サーバー側のユーザー情報でPWを保存しますが、IDFVとかを保存しません
CREATE TABLE `USER_INFO` (
`USER_ID` varchar(32) NOT NULL COMMENT 'ユーザーID',
`PASSWORD` varchar(32) NOT NULL COMMENT 'パスワード',
//...
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='ユーザー情報';
###クライアント側名前/PWリセットロジック
クライアント側に「ユーザー情報がサーバーにない場合、クライアント側ユーザー名とパスワード情報をリセット(==削除)する」ロジックを置きます。
こんなロジックは珍しくないです - 開発環境等でたまたまDBがリセットされていますので、デザイナーとテスターから「簡単にクライアントをリセットさせて」の要望がよく来ます。
//ログインAPIを叩いてみる
error_message = login_to_server();
//サーバーにユーザーが存在しない場合...
if(error_message == USER_NOT_FOUND) {
delete_password_from_keychain(); //...認証用名前/PWを削除
}
サーバー側バグ(一つ)
負荷とかによってサーバーがDBに繋がれない時、例外とかじゃなくてUSER_NOT_FOUNDレスポンスを返します。
//ユーザーIDからユーザー情報を取得
try {
$user = get_user_info($user_id);
} catch (Exception $e) { //<-- バグはここ - 例外種類を確認ぜす、どんな例外でもUSER_NOT_FOUNDを返す
return new Response(USER_NOT_FOUND);
}
##滅亡への流れ
-
本番が公開されて、最初の日から人気
-
人気なので、負荷でDBが落ちてしまう
-
DBが落ちたせいで、ログインAPIはUSER_NOT_FOUNDレスポンスを返す
-
クライアント側がユーザーの名前とパスワードを削除する
-
数分に数千、数万人がログインAPIを叩いてパスワードをなくす
-
滅亡
「実際の話」は他のゲームでも意外と起きられる理由
「実際の話」系現象は、うちと関係ないチームでもまた起きたらしいです - 間違いなくバグですが、初心者チームで負荷時レスポンスは確認されない時が多いです(別な話ですが、負荷テストが大事!)
なお、「実際の話」より恐ろしいなのは、上記以外のバグもpw削除を呼び起こせます。クライアント側ロジックミス、pw上書きなど。特定なシチュエーションで潜んだバグが動き始める場合、同時に数万人のpwが消える結果は同じです。
#対策
こちらの対策として、端末に保存するもの以外の緊急紐付きを用意する - IDFVとか、Facebookアカウントとか。
IDFVも100%信頼できません。どんなIDでも、事情によって問題が起きるかもしれません(数年前の例ですがいきなりAppleがAdvertising IDの利用を禁止にしました - 間違って認証内でAdvertising IDを使っていたゲームはいきなり申請通らなくなりました)。ですが、重要なのは、IDFVとキーチェインデータの両方が同時に使えなくなる可能性はかなり低いです。(と信じたい ^^; ) 問題があったら、どれかから復活でるはずです。(と信じたい ^^; )
あと、まあ負荷テストは大事ですね^^