見出し画像

【Nuxt.js】Firebase Auth × Cloud Firestore ログインアカウントの送信と取得を考える②

🎈 WPでも公開中です
https://wp.me/pc9NHC-1mn

#vue #nuxt #プログラミング #エンジニア

前置き

こちらの続きです。

ルール変更して安全な状態を作りたい❗️
ログインユーザーかつ
送信したデータ内のuidと
authで取得しているuidが
一致する場合のみ
読み書きしたい❗️

ということでやっていきます。

ルールの確認とコード修正

##ルールの前提

条件を書かなければfalseです。
この場合はcitiesコレクション内の
全てのドキュメントの読み書きはできても
hogehogeコレクションなど
別のコレクションの読み書きは
一切できません。
安心💫☝️

rules_version = '2';
service cloud.firestore {
 match /databases/{database}/documents {
   match /cities/{city} {
     allow write: if true;
   }
 }
}

##前回の物をチェック

💁‍♀️ルールは現在こらち

rules_version = '2';
service cloud.firestore {
 match /databases/{database}/documents {
   match /task/{uid} {
     allow read, write: if request.auth != null && request.auth.uid == resource.data.uid;
   }
 }
}

前の記事の1番下、
修正コードが間違っていたので、
ルール変更前の成功コード②をそのまま使用

export const actions = {
 async getData({ commit }) {
   try {
     const user = this.$fire.auth.currentUser
     const querySnapshot = await this.$fire.firestore
       .collection('task')
       .where('uid', '==', user.uid)
       .get()
     const todos = []
     querySnapshot.forEach((doc) => {
       const data = doc.data()
       todos.push(data)
     })
     commit('setData', todos)
   } catch (error) {
      console.log(error)
   }
 },
}

これでルール変更前の取得ができました。

しかし❗️

書き込みで権限なしのエラーが起きました💥✍️
つまり取得のルールに問題はなさそう…

しかしここには読み取りの注意はあっても
書き込みについては何も書かれていない…
データを安全にクエリする

##書き込みのみtrueにしてみる

試しに変更したら、
書き込みと読み取り
両方うまく行きました。

service cloud.firestore {
 match /databases/{database}/documents {
   match /task/{task} {
     allow read:  if request.auth != null && request.auth.uid == resource.data.uid;
     allow write: if true;
   }
 }
}

まだ送信してないのに
resouce.data.uidと
一致しないから❓
と思いましたが、
公式のサンプルコードに
書いてますからねぇ…。

##ワイルドカード、再帰ワイルドカード

そしてここの下の方を見ていくと…
readとwriteの指定場所が違う👀
データを安全にクエリする

rules_version = '2';
service cloud.firestore {

 match /databases/{database}/documents {
   // Authenticated users can query the posts collection group
   // Applies to collection queries, collection group queries, and
   // single document retrievals
   match /{path=**}/posts/{post} {
     allow read: if request.auth != null;
   }
   match /forums/{forumid}/posts/{postid} {
     // Only a post's author can write to a post
     allow write: if request.auth != null && request.auth.uid == resource.data.author;

   }
 }
}

{path=**}は再帰ワイルドカード
バージョンによる注意も書いてあります。
任意の深い階層にも
適応されるというものです。

###ワイルドカードと再帰ワイルドカードの違い

match/cities/{city}
citiesコレクションに一致する
全てのドキュメントに適応
/cities/SF
/cities/NYC
などなど

match/cities/{city}/{document=**}
citiesコレクション内の
全てのドキュメントの
全てのサブコレクションに適応。

この辺が参考になりそう…
と思って色々ためしたけども
ダメでした😯
つまり原因は他にある。
Firestore rules tips
CollectionGroupのFirebaseError: Missing or insufficient permissionsで躓いたときの対処法

##request.resource.data

これを見て上手くいきました!!!
データの検証

書き込みの場合、
まだfirestoreにないデータを送るので
requestが必要ということみたいです。
なので、writeではrequestをつければ解決🙌💕

rules_version = '2';
service cloud.firestore {
 match /databases/{database}/documents {
   match /task/{task} {
     allow write: if request.auth != null && request.auth.uid == request.resource.data.uid;
     allow read: if request.auth != null && request.auth.uid == resource.data.uid;
   }
 }
}


成功ルールとコード

firestoreのルールと
vuex actionsのコードはこちら

rules_version = '2';
service cloud.firestore {
 match /databases/{database}/documents {
   match /task/{task} {
     allow write: if request.auth != null && request.auth.uid == request.resource.data.uid;
     allow read: if request.auth != null && request.auth.uid == resource.data.uid;
   }
 }
}
export const actions = {
 async getData({ commit }) {
   try {
     const user = this.$fire.auth.currentUser
     const querySnapshot = await this.$fire.firestore
       .collection('task')
       .where('uid', '==', user.uid)
       .get()
     const todos = []
     querySnapshot.forEach((doc) => {
       const data = doc.data()
       todos.push(data)
     })
     commit('setData', todos)
   } catch (error) {
      console.log(error)
   }
 },
}

index.vueで
getDataするようにして
実際表示するul>liのコンポーネントで
gettersで中身を表示

<script>
export default {
 async fetch({ store }) {
   await store.dispatch('getData')
 },
}
</script>
<script>
export default {
 computed: {
   todos() {
     return this.$store.getters['todos']
   },
 },
}
</script>


まとめ

取得で.whereを使うだけでも
セキュリティを高めることはできましたが、
やはりルールを設定して
強固にしていくことも必要ですよね🌟

ルールは難しそうと感じましたが、
これらを理解しておけば
簡単なルールは設定できます✨

・firestoreへの送信データの構成
・それに合わせたワイルドカードなど
・用意されているrequest.authなどの変数

🎈 WPでも公開中です
https://wp.me/pc9NHC-1mn

この記事が気に入ったらサポートをしてみませんか?