最近Firebaseを使うことが多くなったのですが,グループ認証に悩んだのでメモしときます.
##グループ認証の方法
Firebase databaseのデータを直接Storageが参照できればいいのですが,それはできません.
なので,仲介役としてAuthのCustomClaimを使います.
CustomClaimは本来,有料会員のフラグを保存したりするものらしいので,チョット使い方が違うような気もしますが,Storageから参照できるものが他にないのでこれを使います.
(一応,公式ドキュメントにもこの手法で書いてありました)
##作り方
###前提
Firestore databaseにユーザー情報があったとします.
{
users:{
userA : {
groups : {
groupA : true
groupB : true
}
},
userB : {
groups : {
groupB : true
groupC : true
}
}
}
}
この情報をuserAはuserAのCustomClaimに,userBはuserBのCustomClaimにいれます.
CustomClaimはadmin権限がないといじれないので, Cloud Functionsで実行します.
cloud functionの設定
exports.updateUserGroupGrant = functions.database.ref('/users/{userId}/groups')
.onWrite(event => {
return refreshCustomClaims(event.params.userId);
});
function refreshCustomClaims(userId){
return admin.database().ref('/users/' + userId + "/groups").once('value').then((snapshot) => {
var claim = {};
for (var key in snapshot.val()){
claim[key] = true;
}
return admin.auth().setCustomUserClaims(userId, claim);
});
}
databaseを監視し,/users/{userId}/groups
が何か変化あったら`refreshCustomClaims
を呼びます
refreshCustomClaims
では引数で渡されたuserId
のclaimを作成し,admin.auth().setCustomUserClaims
で保存しています
strageの設定
Strageのルールではrequest.auth.token
でclaimが取れるので,そこの値を使って認証します.
request.auth.token[groupId]
と言う書き方で変数を組み込むことができます
※ドキュメントの記載を見つけられていないので,動作保証はされないかもしれません
service firebase.storage {
match /b/{bucket}/o {
match /groups/{groupId} {
match /{path=**} {
allow read, write: if request.auth!=null
&& request.auth.token[groupId] == true;
}
}
}
}
これでdatabaseを使ってstrageでの認証ができました.
##注意点
claimは認証以外に使わないでください(データは入れないでください)と公式ドキュメントに書いてあります.
今回のは認証に使っているので違反しているわけではないのですが,データに対応していない=たくさん情報を詰め込むことを想定していない ということだと思うので,
大量のグループがある場合,この方法はちょっと見直さないといけないかもしれません.