Firebase Googleログイン初回ログインと継続ログインで処理の分岐
Firebaseの認証機能って便利だけど思うように動かないことありますよね。
今回やること
Googleログインを利用するユーザーがアプリ上でプロフィール変更を行なったにも関わらず、 次回ログインした時に初期設定になってしまうことを解消します。
前提として
- Firestoreを少しでも触ったことがある方を対象としてます。
- データはFirestoreの
users/{uid}
の中に保存します。 - React/ReduxToolkit + Typescriptで書いてます。
ユーザーデータの永続化における問題点
以下のコードでGoogleログインを行なった場合
export const signInGoogle = (): AppThunk => { return async (dispatch): Promise<void> => { return auth.signInWithPopup(provider).then((result) => { const user = result.user if (user) { const uid = user.uid const timestamp = FirebaseTimestamp.now() const userInitialData = { uid: uid, username: user.displayName, email: user.email, role: 'customer', updated_at: timestamp, created_at: timestamp, } usersRef .doc(uid) .set(userInitialData) .then(()=>dispatch.push('/')) } }) } }
写真のように登録される。
Authの画面
Firestoreの画面
一見問題ないですが、これだとアプリ側でプロフィールを変更した時でも常にuserInitialData
で定義した情報に書き換わってしまう。
例えばrole
をadmin
などに変更してアプリ内で権限の制御を行う場合にログインするたびに規定の設定に戻ってしまう。
対処方法
FirebaseのAuth.currentUserにはmetadataというものがあって
そこには作成日時
とログイン日時
が記録されていることがわかった。
そのため作成日時とログイン日時が一致している時は新規作成。
一致していなければ継続ログインということが判断できるため、
新規ログインの時のみ既存のデータをセットしておけば、アプリ側でユーザーがプロフィールを変更した場合でも、
変更された状態が維持されることがわかった。
export const signInGoogle = (): AppThunk => { return async (dispatch): Promise<void> => { return auth.signInWithPopup(provider).then((result) => { const user = result.user if (user) { const uid = user.uid const timestamp = FirebaseTimestamp.now() // 作成日時とログイン日時 const creationTime = user?.metadata.creationTime const lastSignInTime = user?.metadata.lastSignInTime if (creationTime == lastSignInTime) { const userInitialData = { uid: uid, username: user.displayName, email: user.email, role: 'customer', updated_at: timestamp, created_at: timestamp, } usersRef .doc(uid) .set(userInitialData) .then(()=>dispatch.push('/')) } }.then(()=>dispatch.push('/')) }) } }
終わりに
他にベストな方法あれば教えていただければうれしいですが結構悩んだのちに.
最後はFirebaseのドキュメントに解決してもらうという。
ドキュメントの偉大を書いた方に感謝を伝えます。