Firebase Databaseでパスにuidを含めたユーザ権限周りをFirestoreでやるには
あきらめましょう
通常のKVSのようにドキュメントにオーナーのユーザIDを含めてセキュリティルールでオーナー以外を弾く設定をしましょう
おわり
.
.
.
.
.
.
っとしても良いのだけどどうせならexampleでも
まずベースとなるモデルを定義します.
このモデルをベースにモデルを作ります.
// BaseModel.ts
export default abstract class BaseModel {
// ドキュメントオーナーのID
readonly userID: string;
// ドキュメントのID
id: string | null;
// ドキュメントの作成・更新日時
timestamp: Date;
constructor(userID: string, timestamp: Date) {
this.userID = userID;
this.timestamp = timestamp;
}
// Firestoreに保存するとき用
abstract toJSON(): Object;
}
toJSON
はデータベースに保存する際に特定のプロパティのみを保存するためにあります.
これを定義すればid
を保存対象から無視できます.
このBaseModel
を継承したToDoModel
を実装します.
// ToDoModel.ts
import BaseModel from './BaseModel';
export default class ToDoModel extends BaseModel {
// タイトル
title: string;
// ToDoが完了したかどうか
completed: boolean = false;
constructor(userID: string, title: string, timestamp: Date) {
super(userID, timestamp);
this.title = title;
}
toJSON(): Object {
// NOTICE: idはfirestore上で自動で割り振られるのでわざわざデータとして格納しなくてよい
return {
userID: this.userID,
title: this.title,
completed: this.completed,
timestamp: this.timestamp,
};
}
}
ここまで実装して重要なのはuserID
を定義しておくことです.
このuserID
がセキュリティルール
でドキュメントの所有者かどうかチェックを行うのに必要になります.
さて次にセキュリティルール
を定義してあげます.
RTDBの場合リファレンスパスは/todos/$uid/<todoDoc.id>
なので
// database.rules.json
{
"rules": {
"todos": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
}
}
でドキュメントの所有者のみが閲覧・更新が可能になります.
つづいて,
Firestoreの場合はコレクションがtodos
となり,
// firestore.rules
service cloud.firestore {
match /databases/{database}/documents {
match /todos/{todoID} {
allow read, write: if get(/databases/$(database)/documents/todos/$(todoID)).userID == request.auth.uid;
}
}
}
でRTDBどうよう所有者のみが閲覧・更新が可能になります.
走らせる擬似コードも載せておきます. ( ブラウザで走らせるためにはやらなくてはいけないことがそれなりにあるが省略)
// index.ts
import * as firebase from "firebase";
import 'firebase/firestore';
import ToDoModel from './ToDoModel';
const frConfig = {
apiKey: "<API_KEY>",
authDomain: "<PROJECT_ID>.firebaseapp.com",
databaseURL: "https://<DATABASE_NAME>.firebaseio.com",
storageBucket: "<BUCKET>.appspot.com",
};
const firebaseApp = firebase.initializeApp(frConfig);
let rtdb: firebase.database.Database;
let frStore: firebase.firestore.Firestore;
let uid: string;
async function setup():Promise<void> {
try {
const user = await firebaseApp.auth().signInAnonymously();
uid = user.uid;
rtdb = firebaseApp.database();
frStore = firebase.firestore(firebaseApp);
return Promise.resolve();
} catch (e) {
return Promise.reject(e);
}
}
async function rtdbCreate(): Promise<ToDoModel> {
const key = rtdb.ref(`todos/${uid}`).push().key;
const todoDoc = new ToDoModel(uid, '🍣をたくさんたべる (๑•̀ㅂ•́)و✧', new Date());
todoDoc.id = key;
const updates: { [key: string]: any } = {};
updates[`todos/${uid}/${key}`] = todoDoc.toJSON();
try {
await rtdb.ref().update(updates);
} catch (e) {
return Promise.reject(e);
}
return Promise.resolve(todoDoc);
}
async function firestoreCreate(): Promise<ToDoModel> {
const todoDoc = new ToDoModel(uid, '🍣をたくさんたべる (๑•̀ㅂ•́)و✧', new Date());
try {
const todoDocRef = await frStore.collection('todos').add(todoDoc.toJSON());
todoDoc.id = todoDocRef.id;
} catch (e) {
return Promise.reject(e);
}
return Promise.resolve(todoDoc);
}
async function main() {
await setup();
console.log('uid: ', uid);
const result1 = await rtdbCreate();
console.log(result1);
const result2 = await firestoreCreate();
console.log(result2);
}
main();
Firestoreのセキュリティルールに関数を定義できるの便利だけど, これテストしたいときどうするんですかね…
製品版に期待してFirestoreでどんどん実装していきたいと思います(๑•̀ㅂ•́)و✧