【permission-denied】権限エラーが出る原因と確認方法を理解する
このページでやること
このページでは、Firebase / Firestoreでよく出るエラー permission-denied について理解します。
permission-denied は、簡単に言うと、
Firestoreが「この操作は許可されていません」と止めた
という意味です。
エラーが出ると焦りますが、原因を順番に見れば確認できます。
今日のゴール
permission-denied が出たときに、どこを確認すればよいか分かるようにします。
permission-deniedが出た
↓
ログイン状態を確認
↓
Firestore Rulesを確認
↓
uidを確認
↓
teamIdを確認
↓
members/{uid}/roleを確認
↓
保存場所を確認
npmや環境変数は必要?
このページでは、npmは使いません。
環境変数も設定しません。
確認する場所は、この3つです。
Flutterアプリ
Firebase Console
Firestore Rules
permission-deniedとは?
permission-denied は、Firestore Security Rulesによって操作が拒否されたときに出ます。
たとえば、次のような場合です。
未ログインでデータを読もうとした
自分以外のusers情報を書き換えようとした
チームメンバーではないのにtasksを読もうとした
viewerなのにタスクを作成しようとした
memberなのにタスクを削除しようとした
つまり、Firestore側で「この人には許可できません」と判断された状態です。
まず覚えること
permission-denied は、必ずしも悪いエラーではありません。
権限のない人を止められている場合は、正常です。
viewerがタスク削除しようとした
↓
permission-denied
↓
正しく守れている
ただし、許可したい操作まで止まっている場合は、設定やデータを確認します。
1. まずログイン状態を確認する
Step 1:ログインしているか確認する
Firestore Rulesでよく使う条件がこれです。
request.auth != null
意味はこうです。
ログインしている人だけOK
そのため、ログインしていないと permission-denied が出ます。
Step 2:Flutter側でログイン状態を確認する
Flutter側では、次のコードでログイン中ユーザーを確認できます。
final user = FirebaseAuth.instance.currentUser;
確認用に、一時的にログを出すならこうです。
final user = FirebaseAuth.instance.currentUser;
debugPrint('現在のuid: ${user?.uid}');
debugPrint('現在のemail: ${user?.email}');
uid が表示されればログイン中です。
現在のuid: abc123
null の場合は、ログインできていません。
現在のuid: null
Step 3:AuthGateを確認する
このアプリでは、AuthGate でログイン状態を見ています。
stream: FirebaseAuth.instance.authStateChanges(),
ログインしていない場合は、LoginPage が表示されます。
未ログイン
↓
LoginPage
ログイン済み
↓
TeamListPage
まず、アプリがログイン済み画面に進んでいるか確認します。
2. Firestore Rulesを確認する
Step 4:Firebase Consoleを開く
ブラウザでFirebase Consoleを開きます。
https://console.firebase.google.com/
今回のプロジェクトを選びます。
Step 5:Rules画面を開く
次の順番で開きます。
Build
↓
Firestore Database
↓
Rules
日本語表示の場合です。
構築
↓
Firestore Database
↓
ルール
Step 6:今どのRulesか確認する
学習中は、まず現在のRulesを確認します。
開発用Rulesなら、こうです。
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
この場合、基本的に permission-denied は出ません。
出る場合は、別のFirebaseプロジェクトを見ている可能性があります。
Step 7:ログイン必須Rulesの場合
ログイン必須Rulesなら、こうです。
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null;
}
}
}
この場合、未ログインだと permission-denied が出ます。
ログイン中なら、基本的に読み書きできます。
3. Firebaseプロジェクトが合っているか確認する
Step 8:違うプロジェクトを見ていないか確認する
意外と多い原因がこれです。
Flutterアプリが使っているFirebaseプロジェクト
↓
Aプロジェクト
Firebase Consoleで見ているプロジェクト
↓
Bプロジェクト
この場合、Rulesを直してもアプリには反映されません。
Step 9:firebase_options.dartを確認する
Flutter側で、次を開きます。
lib/firebase_options.dart
中の projectId を確認します。
projectId: 'your-project-id',
Firebase Consoleで開いているプロジェクトIDと同じか確認します。
Flutter側のprojectId
Firebase ConsoleのprojectId
この2つが同じならOKです。
4. uidを確認する
Step 10:ログイン中のuidを確認する
Firestore Rulesでは、よく request.auth.uid を使います。
これは、ログイン中のユーザーIDです。
Flutter側では、次で確認できます。
final user = FirebaseAuth.instance.currentUser;
debugPrint('uid: ${user?.uid}');
Step 11:Firestoreのuidと一致しているか確認する
たとえば、users/{uid} を確認します。
Firestore Database
↓
users
↓
自分のuid
Flutter側のuidと、FirestoreのドキュメントIDが同じか見ます。
Flutterのuid: abc123
Firestore: users/abc123
同じならOKです。
違う場合、Rulesで拒否されることがあります。
5. usersでpermission-deniedが出る場合
Step 12:usersの保存場所を確認する
ユーザープロフィールはここです。
users/{uid}
本人だけ許可するRulesの場合、条件はこうなります。
request.auth.uid == userId
つまり、
ログイン中のuid
↓
abc123
アクセス先
↓
users/abc123
このように一致している必要があります。
usersでよくある原因
| 原因 | 確認すること |
|---|---|
| 未ログイン | currentUser が null ではないか |
| uid違い | users/{uid} のIDがログイン中uidと同じか |
| usersが作られていない | 新規登録時のプロフィール保存を確認 |
| Rulesが厳しい | usersルールを確認 |
6. teamsでpermission-deniedが出る場合
Step 13:teamsの保存場所を確認する
チーム情報はここです。
teams/{teamId}
チーム一覧では、次のように取得しています。
FirebaseFirestore.instance
.collection('teams')
.where('memberIds', arrayContains: uid)
.snapshots()
ここで大事なのが memberIds です。
Step 14:memberIdsに自分のuidがあるか確認する
Firebase Consoleで確認します。
Firestore Database
↓
teams
↓
対象のteamId
↓
memberIds
中に自分のuidが入っているか確認します。
memberIds: [自分のuid]
入っていない場合、チーム一覧に出なかったり、Rulesで拒否されたりします。
teamsでよくある原因
| 原因 | 確認すること |
|---|---|
| memberIdsにuidがない | teams/{teamId}/memberIds を確認 |
| teamIdが違う | 開いているチームIDを確認 |
| ログインuidが違う | currentUser.uid を確認 |
| Rulesがチームメンバーだけ許可 | membersやmemberIdsを確認 |
7. membersでpermission-deniedが出る場合
Step 15:membersの保存場所を確認する
チームメンバー情報はここです。
teams/{teamId}/members/{uid}
ここに、チーム内の権限が入っています。
role: owner
role: admin
role: member
role: viewer
Step 16:自分のmembersドキュメントがあるか確認する
Firebase Consoleで確認します。
Firestore Database
↓
teams
↓
対象のteamId
↓
members
↓
自分のuid
自分のuidのドキュメントがなければ、チームメンバーとして扱えません。
Step 17:roleを確認する
members/{uid} の中の role を確認します。
role: owner
または、
role: admin
role: member
role: viewer
権限操作で止まる場合は、この role が原因かもしれません。
membersでよくある原因
| 操作 | 必要なrole |
|---|---|
| メンバー追加 | owner または admin |
| 権限変更 | owner |
| メンバー削除 | owner |
| メンバー一覧を見る | チームメンバー |
8. tasksでpermission-deniedが出る場合
Step 18:tasksの保存場所を確認する
タスク情報はここです。
teams/{teamId}/tasks/{taskId}
タスク作成・編集・削除では、権限によって許可が変わります。
Step 19:自分のroleを確認する
タスク操作で止まる場合は、まず自分のroleを確認します。
teams/{teamId}/members/{自分のuid}/role
設計ではこうです。
| 操作 | owner | admin | member | viewer |
|---|---|---|---|---|
| タスク作成 | ○ | ○ | ○ | × |
| タスク編集 | ○ | ○ | ○ | × |
| タスク削除 | ○ | ○ | × | × |
tasksでよくある原因
| 操作 | permission-deniedの原因 |
|---|---|
| タスク作成 | viewer になっている |
| タスク編集 | viewer になっている |
| タスク削除 | member または viewer になっている |
| タスク一覧表示 | チームメンバーではない |
| タスク取得 | teamIdが違う |
9. コードの参照先を確認する
Step 20:collection名を確認する
Firestoreでは、文字が1文字違うだけで別の場所になります。
正しい名前はこちらです。
users
teams
members
tasks
悪い例です。
user
team
member
task
単数形と複数形を間違えると、データが見つからなかったり、Rulesに合わなかったりします。
Step 21:teamIdを確認する
タスクやメンバーは、必ずチームの中にあります。
teams/{teamId}/members
teams/{teamId}/tasks
teamId が違うと、別チームを見に行ってしまいます。
Step 22:doc.idを確認する
タスクやメンバーを更新・削除するときは、正しいIDを使っているか確認します。
doc.id
メンバーの場合は、基本的に uid がドキュメントIDです。
members/{uid}
タスクの場合は、自動生成された taskId です。
tasks/{taskId}
10. 一時的に開発用Rulesで切り分ける
Step 23:Rulesが原因か確認する
原因が分からないときは、一時的に開発用Rulesで確認します。
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
これでエラーが消える場合は、Rulesが原因の可能性が高いです。
Step 24:それでも消えない場合
開発用Rulesでもエラーが消えない場合は、Rules以外を疑います。
Firebaseプロジェクトが違う
collection名が違う
teamIdが違う
uidが違う
Firestoreにデータがない
Firebase初期化が違う
この順番で確認します。
確認フローチャート
permission-deniedが出た
↓
ログインしている?
├─ いいえ → ログインする
└─ はい
↓
Firebaseプロジェクトは合っている?
├─ いいえ → projectIdを合わせる
└─ はい
↓
Rulesを確認した?
├─ いいえ → Firebase ConsoleでRulesを見る
└─ はい
↓
自分のuidは正しい?
├─ いいえ → currentUser.uidを確認
└─ はい
↓
チーム操作ならmembers/{uid}がある?
├─ いいえ → メンバー追加・memberIdsを確認
└─ はい
↓
roleは操作に必要な権限?
├─ いいえ → roleを確認
└─ はい
↓
teamId / taskId / collection名を確認
よくあるエラーと直し方
| エラー内容 | よくある原因 | 確認場所 |
|---|---|---|
permission-denied | 未ログイン | FirebaseAuth.instance.currentUser |
permission-denied | Rulesが厳しい | Firebase Console → Rules |
permission-denied | uidが違う | users/{uid} |
permission-denied | チームメンバーではない | teams/{teamId}/members/{uid} |
permission-denied | roleが足りない | members/{uid}/role |
permission-denied | 別プロジェクトを見ている | firebase_options.dart |
permission-denied | memberIdsにuidがない | teams/{teamId}/memberIds |
初心者向け:まず見る場所3つ
読むのが大変な人は、まずここだけ見てください。
1. ログインしているか
2. Firebase ConsoleのRules
3. Firestoreのmembers/{自分のuid}/role
この3つで、かなりの原因が分かります。
確認用ログコード
Flutter側で一時的に確認したい場合は、処理の前に入れます。
final user = FirebaseAuth.instance.currentUser;
debugPrint('--- 権限確認 ---');
debugPrint('uid: ${user?.uid}');
debugPrint('email: ${user?.email}');
debugPrint('teamId: ${widget.teamId}');
タスク一覧やメンバー一覧の画面で確認すると便利です。
確認が終わったら、消してOKです。
permission-deniedが出たときの考え方
大事なのは、焦らず順番に見ることです。
誰が
どこのデータに
何をしようとして
Rulesに止められたのか
この4つで考えます。
例です。
誰が:member
どこ:teams/{teamId}/tasks/{taskId}
何を:delete
結果:memberは削除できないので拒否
この場合、Rulesは正しく動いています。
最短作業まとめ
1. ログイン状態を見る
final user = FirebaseAuth.instance.currentUser;
debugPrint('uid: ${user?.uid}');
2. Firebase ConsoleでRulesを見る
Build
↓
Firestore Database
↓
Rules
3. 自分のroleを見る
teams/{teamId}/members/{自分のuid}/role
4. memberIdsを見る
teams/{teamId}/memberIds
5. 一時的に開発用Rulesで切り分ける
allow read, write: if true;
チェックリスト
□ permission-deniedの意味を理解した
□ ログイン状態を確認した
□ currentUser.uidを確認した
□ Firebase ConsoleのRulesを確認した
□ firebase_options.dartのprojectIdを確認した
□ users/{uid}を確認した
□ teams/{teamId}/memberIdsを確認した
□ teams/{teamId}/members/{uid}を確認した
□ roleを確認した
□ tasksのteamIdを確認した
□ collection名を確認した
□ 必要なら開発用Rulesで切り分けた
ミニ確認問題
Q1. permission-denied は何のエラーですか?
回答
Firestore Security Rulesによって、読み書きが拒否されたときのエラーです。
Q2. 未ログインでFirestoreを読むと、なぜ拒否されますか?
回答
Rulesに request.auth != null がある場合、ログインしていない人は許可されないからです。
Q3. チーム一覧に出ないとき、まず確認する配列は何ですか?
回答
memberIds です。
teams/{teamId}/memberIds
Q4. タスク削除で拒否されたとき、確認する項目は何ですか?
回答
自分の role です。
teams/{teamId}/members/{自分のuid}/role
member や viewer はタスク削除できません。
Q5. 開発用Rulesにしてもエラーが消えない場合、何を疑いますか?
回答
Rules以外の原因を疑います。
Firebaseプロジェクト違い
collection名違い
teamId違い
uid違い
データ未作成
このページのまとめ
permission-deniedは、Firestore Rulesに拒否されたエラー。- まずログイン状態を見る。
- 次にFirebase ConsoleでRulesを見る。
- Firebaseプロジェクトが合っているか確認する。
- チーム操作では
memberIdsとmembers/{uid}/roleが重要。 viewerは作成・編集・削除できない。memberはタスク削除できない。- 開発用Rulesで一時的に切り分けできる。
- このページではnpmや環境変数は不要。
次のページでやること
次のページでは、users/{uid} のSecurity Rulesを作ります。
本人だけが自分のプロフィールを読み書きできるようにします。
