シェル(@takasqr)のブログ

【Firebase】カスタムクレーム(Custom Claims)で管理者ユーザーを作る

はじめに

  • 特定のユーザーだけ、Firestore、Firebase strageのアクセス権限を強くしたい
  • 特定のユーザーだけアクセスできるページを作りたい

といった、Authenticationのユーザーにラベルを付けたい時にFirebase Admin SDKのクレームを使うと便利です。

この記事を書いた人

@takasqr アプリケーション開発が大好きなエンジニア。Vue、Swift、Electrom などでアプリを作って公開している。AWS や Firebase などのクラウドサービスも好き。

作ったアプリKeyScript

導入

カスタムクレームをセットする。

admin
  .auth()
  .setCustomUserClaims(uid, { admin: true })
  .then(() => {
    // 
  });

例だとAdminというクレームに対してtrueを設定しています。

クライアントで取得するには、

firebase.auth().currentUser.getIdTokenResult()
  .then((idTokenResult) => {
     // Confirm the user is an Admin.
     if (idTokenResult.claims.admin) {
       // adminがtrueだったら
     } else {
       // adminがfalseだったら
     }
  })
  .catch((error) => {
    console.log(error);
  });

セキュリティルールの例。

match /test/{test} {
      allow read: if request.auth.token.admin == true;
      allow create: if request.auth.uid != null;
    }

これはtestコレクションにFirebase Authのユーザーならだれでもデータを作ることができる。だが、データを読み取るにはadminクレームを持っているユーザーじゃなければならない。

という例。

応用

Firestoreにuidを登録すると、自働的にカスタムクレームを登録してくれる関数です。 Firebase Functionsにデプロイします。

const functions = require('firebase-functions')
const admin = require('firebase-admin')

exports.set = async function (uid, claims) {
  let returnValue = null
  const user = await admin.auth().getUser(uid)
  const updatedClaims = user.customClaims || {}

  for (const property in claims) {
    if (Object.prototype.hasOwnProperty.call(claims, property)) {
      updatedClaims[property] = claims[property]
    }
  }
  await admin.auth().setCustomUserClaims(uid, updatedClaims)
    .then(function () {
      returnValue = Promise.resolve(true)
    })
    .catch((error) => {
      functions.logger.error(error)
      returnValue = Promise.resolve(false)
    })
  return returnValue
}
const functions = require('firebase-functions')
const CustomClaimsEx = require('./CustomClaimsEx')

exports.setAdminClaim = functions.firestore
  .document('adminClaims/{adminClaimsId}')
  .onCreate(async (snap, context) => {
    CustomClaimsEx.set(snap.data().uid, { admin: true })
  })
const functions = require('firebase-functions')
const CustomClaimsEx = require('./CustomClaimsEx')

exports.unsetAdminClaim = functions.firestore
  .document('adminClaims/{adminClaimsId}')
  .onDelete(async (snap, context) => {
    CustomClaimsEx.set(snap.data().uid, { admin: false })
  })

カスタム クレームとセキュリティ ルールによるアクセスの制御 | Firebase