Firestore权限异常:exclusiveA读取被拒,creditCard为false仍无法访问
问题分析与解决方案
核心问题原因
- 权限操作不匹配:你的Flutter代码对
exclusiveA执行的是集合查询(snapshots()返回QuerySnapshot),但安全规则中仅声明了allow get:(仅允许单文档读取),集合查询需要allow list:权限,这是权限被拒的直接原因。 - 路径变量未定义:规则中访问
exclusiveB文档的路径/users/{docId}/userB/{docIdB}/exclusiveB/$(request.auth.uid)里的{docIdB}是未在match语句中定义的变量,Firestore无法解析该路径,导致无法正确获取creditCard字段值。 - 文档ID与UID不匹配:从Flutter代码看,
exclusiveB的文档是通过where('uid', isEqualTo: currentUserID)查询的,说明文档ID≠用户UID,但规则中直接用request.auth.uid作为exclusiveB的文档ID,导致无法定位到正确的文档。
解决方案
1. 调整数据结构(推荐)
将exclusiveB的文档ID设置为用户UID,这样可以直接通过用户UID定位到对应文档,简化规则逻辑。
2. 修正安全规则
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /users/{docId} { allow read; match /userA/{userADocId} { allow read; match /exclusiveA/{exclusiveADocId} { // 同时允许单文档读取和集合查询 allow get, list: if request.auth != null && get(/databases/$(database)/documents/users/$(docId)/userB/{userBDocId}/exclusiveB/$(request.auth.uid)).data.creditCard == false; } match /otherDetails/{id} { allow read: if request.auth.uid == resource.data.id; } } match /userB/{userBDocId} { allow read; match /exclusiveB/{exclusiveBDocId} { allow get: if exclusiveBDocId == request.auth.uid; } match /otherDetails/{id} { allow read: if request.auth.uid == resource.data.id; } } } } }
若无法修改
exclusiveB的文档ID,Firestore规则不支持直接查询集合验证字段,建议将creditCard状态存储到用户根文档中,或调整数据结构让exclusiveB文档ID与UID绑定。
3. Flutter代码优化
解决currency异步初始化导致的查询条件为空问题:
@override Widget build(BuildContext context) { return FutureBuilder( future: matchDetails(), builder: (context, futureSnapshot) { if (futureSnapshot.connectionState != ConnectionState.done) { return const CircularProgressIndicator(); } if (currency == null) { return const Text("无法获取用户货币信息"); } return StreamBuilder<QuerySnapshot>( stream: _dataSource.where('preferredCurrency', isEqualTo: currency).snapshots().distinct(), builder: (context, snapshot) { if (!snapshot.hasData) { return const CircularProgressIndicator(); } final retrievedData = snapshot.data!.docs; // 重置变量避免旧数据残留 maxSpeed = null; vehicleTitle = null; pullStrength = null; vehicleMake = null; pCurrency = null; for (var specific in retrievedData) { maxSpeed = specific['topSpeed']; vehicleTitle = specific['vehicleName']; pullStrength = specific['horsePower']; vehicleMake = specific['vehicleBrand']; pCurrency = specific['preferredCurrency']; } return Column( children: [ Text('The vehicle\'s maximum speed = $maxSpeed.'), Text('The vehicle\'s pulling strength = $pullStrength bph.'), Text('The vehicle\'s brand is $vehicleMake, and its model-name is $vehicleTitle.'), ], ); }, ); }, ); }
内容的提问来源于stack exchange,提问作者mathems32
相关产品推荐
相关产品推荐

