Firebase のユーザーに個別に権限を割り振りたい要件は多そう。すでに似たような記事はたくさんありますが、自分も実装方法を調べたので文章にしておきます。
実装イメージ
Firebase Auth のカスタムクレームを使用します。Firebase ユーザーオブジェクトに独自のプロパティを生やすことができる機能です。
Firestore にユーザー別にどんな権限(=カスタムクレーム)を持っているかを格納しておく user-claims
というコレクションを用意します(コレクション名は任意)。
Functions for Firebase で Firestore の user-claims
コレクションへの変更イベントをリッスンして、その内容を Firebase Auth のカスタムクレームに同期させます。 user-claims
コレクションへの書き込みは Firebase コンソールから直接でも Admin サーバー経由でもいけます。
実装後の使い道
クライアント環境でユーザーに付与されたカスタムクレームを参照して、画面の出し分けに使えたりします。
const isAdminUser = getAuth() .currentUser?.getIdTokenResult(true) .then(idToken => idToken.claims.isAdminUser); // `isAdminUser` の部分は好きなキー名にできる。ただし型はつかない console.log(isAdminUser); // user-claims コレクションで付与した値
また、Callable Functions のリクエスト検証で認証チェックの 1 つとして利用できます。
export const myFunction = functions.https.onCall(async (data, context) => { if (context.auth?.token.isAdminUser !== true) { throw new functions.https.HttpsError( "permission-denied", "The function must be called by admin user.", ); } // do something });
他にも使い道の可能性は無限大です。知らんけど。
実装方法
Firestore の user-claims
コレクションに登録されたデータを Firebase Auth のカスタムクレームにセットする処理を Functions が担当しますので、Functions のコードを書いていきます。
user-claims
コレクション内のドキュメントデータとカスタムクレームを完全に同期するには、
user-claims
コレクションにドキュメントが作成されたらカスタムクレームに書き込むuser-claims
コレクションのドキュメントが更新されたらカスタムクレームに書き込むuser-claims
コレクションのドキュメントが削除されたらカスタムクレームも削除する- ユーザーが削除されたら
user-claims
コレクションのドキュメントも削除する
の 4 つの処理が必要になります。 user-claims
コレクションのドキュメント ID はユーザー ID とします。
export const addUserClaims = functions.firestore .document("user-claims/{docId}") .onCreate(userClaims => getAuth().setCustomUserClaims(userClaims.id, userClaims.data()), ); export const updateUserClaims = functions.firestore .document("user-claims/{docId}") .onUpdate(userClaims => getAuth().setCustomUserClaims(userClaims.after.id, userClaims.after.data()), ); export const removeUserClaims = functions.firestore .document("user-claims/{docId}") .onDelete(userClaims => getAuth().setCustomUserClaims(userClaims.id, null)); export const removeUserClaimDoc = functions.auth.user().onDelete(user => { getFirestore().collection("user-claims").doc(user.uid).delete({ exists: false }); });
尚、本記事ではユーザーが存在するが対応する user-claims
のドキュメントは存在しない状態を許容するものとします。
はい、これで Firestore の user-claims
にドキュメントを追加すれば同じ ID のユーザーに対して自由に権限が割り振れるようになりました。
あとは Firebase コンソールなり Admin 環境から user-claims
にユーザー ID をドキュメント ID としたドキュメントを追加していけばいいでしょう。
ちなみに、わざわざ Functions や Firestore を使わなくても Admin 環境で setCustomUserClaims
を呼び出せばいいのですが、Firestore と同期されていれば Firebase コンソールからでも登録削除ができるので便利になりますし、カスタムクレームの内容を Firestore のコレクションで一元管理できるのでわかりやすいです。
まとめ
Firebase Auth, Firestore, Functions for Firebase を組み合わせて、ユーザーに権限を割り振る方法を紹介しました。
実装方法を簡単にまとめると
- Functions で Firestore の変更イベントを検知して、Firebase Auth のカスタムクレームに書き込む
- 書き込まれたカスタムクレームをクライアントや Callable Functions で使う
です。
それではよい Firebase ライフを!