【Firebase】カスタムクレーム(Custom Claims)で管理者ユーザーを作る
はじめに
- 特定のユーザーだけ、Firestore、Firebase strageのアクセス権限を強くしたい
- 特定のユーザーだけアクセスできるページを作りたい
といった、Authenticationのユーザーにラベルを付けたい時にFirebase Admin SDK
のクレームを使うと便利です。
この記事を書いた人
@takasqr アプリケーション開発が大好きなエンジニア。Vue、Swift、Electrom などでアプリを作って公開している。AWS や Firebase などのクラウドサービスも好き。
導入
カスタムクレームをセットする。
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 })
})