UIDをドキュメントIDの代わりに使う理由
詳しく書いてみようと思った...
詳しくと記事のタイトルに書いてしまいましたが、実際のところは、これで詳しくというのは、個人の考えです🤔
結論をいうと、Firestoreのセキュリティールールを書きやすくするためなんですよね。
なぜ書きやすくなるのか?
Firestoreにデータを保存すると、ランダムなIDが作られるじゃないですか💁
collection.add()ですね。でもこれだと、誰のデータか特定することができないですね。だってランダムに生成されているんだもの!
Firestoreを使うときですが、基本はAuthenticationと組み合わせます。
collection.doc(uid).set()だと特定のユーザーのデータとして保存することができます。これは1個のデータを1度けしか保存しません。2回目に実行するとupdate(上書き)されます。
公式にも書いてあるかな?
これは、認証済みのコンテンツ所有者にのみアクセスを制限するというルールです。データの読み取りや書き込みを行うことができるのは 1 人のユーザーに限られます。そのユーザーの ID がデータパスに含まれています。
このルールが機能するケース: このルールが適切に機能するのは、ユーザーによってデータがサイロ化されている場合です。つまり、データにアクセスする必要がある唯一のユーザーが、そのデータを作成した本人である場合です。
このルールが機能しないケース: このルールセットが機能しないのは、同じデータに対して複数のユーザーが書き込みや読み取りを行う必要がある場合です。つまり、複数のユーザーがデータを上書きしようとする場合、ユーザー自身が作成したデータでもそれにアクセスできなくなってしまいます。
このルールを設定する: データの読み取りや書き込みへのアクセスをリクエストしているユーザーがそのデータの所有者であることを確認するルールを作成します。
service cloud.firestore {
match /databases/{database}/documents {
// Allow only authenticated content owners access
match /some_collection/{userId}/{documents=**} {
allow read, write: if request.auth != null && request.auth.uid == userId
}
}
}
例を出すと、こんな感じのコードになりますね
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:uuid_application/model/post_model.dart';
class ServiceClass {
final db = FirebaseFirestore.instance;
final auth = FirebaseAuth.instance;
Future<void> addPost(String nameController) async {
final uid = auth.currentUser?.uid;
final newPost = PostModel(
id: uid,
name: nameController,
);
await db.collection('post').doc(uid).set(newPost.toMap());
}
}
setを使う場合だと、ユーザーのuidを指定して、Firestoreにデータを保存するので、ドキュメントIDが、ランダムなものではなくて、ユーザーアカウントを作成したときのuidが、ドキュメントIDとなります。
taro@co.jpのユーザーUIDが使われる
ログインしてデータを保存してみた!
「おっ一致してますね。」これが、ドキュメントIDとユーザーのuidを一致させるということか!
なるほどなるほど。
こちらがセキュリティールールです
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// postコレクションにログインしているユーザーが書き込み可能
match /post/{uid} {
// ドキュメントIDと書き込みリクエストした認証ユーザーが一致していれば許可
allow create: if request.auth != null;
}
}
}
ユーザーがログインしていたら、データを保存する(書き込みと本では表現されていた)ことができます。
コンソールで、ダミーのデータを使ってセキュリティールールが正しく動いているのかテストすることができます。
セキュリティールールのテストをしてみる
画面左の星マークをクリックしてください。
ルールプレイグランドなるものがありますね。こちらをクリックしてみましょう。そしたら、入力するところがいっぱい出てきましたね。
こちらの項目を選択したり、記入をしてテストができます。
やり方
- 今回やるのは、データの保存なので、シュミレーションタイプをcreateにする。
- 場所のところは、パスを指定します。パスってのは、コレクション名/フィールド名です。今回だと、postコレクションのnameフィールドのことですね。
- ドキュメントを作成のボタンを押して保存するダミーのデータのフィールド名、データの型、値を記入して、完了を押します。
- プロバイダは、google.comのままで、FirebaseUIDは、taro@co.jpさんという方のユーザーUIDを指定します。メールは、taro@co.jpを指定します。
- 名前、電話の項目は、空白のままで、実行ボタンを押します。
成功すると、緑色のログが表示されます。失敗したら赤いログが出てくて、間違ったセキュリティールールを書いているコードの部分に × 印がつきます!
最後に
以前こんな記事を書いていたのを思い出しました。
久しぶりに見てみると、なんでドキュメントIDとUIDを一致させるのかについて解説していませんでした。当時から、セキュリティールールを書きやすくするために、使うということは知っていました。こちらが今回使用したサンプルコード
状態管理は、していなくて初心者向けのログインとデータの追加を学べるだけのサンプルです。
StatefulWidgetとStatelessWidgetしか使ったことないよという人には、丁度良いかもしれません?
昔の私は、モデルクラスすら作ってませんでしたよ😅
Discussion