firebase 调用Firestore的get(/databases/)函数,其中相关数据位于子集合中...出什么事了?

lrpiutwd  于 2023-05-07  发布在  其他
关注(0)|答案(1)|浏览(163)

在Firestore中,我有一个名为'exclusiveB'的子集合中的数据,这个集合的文档的字段是'creditCard',它接受布尔值。
在上面提到的同一个Firestore中,我有另一个名为“exclusiveA”的子集合。
我写了一条安全规则,允许当前用户读取'exclusiveA'集合:如果当前用户具有uid,并且如果关于子集合'exclusiveB'中的当前用户的详细信息确认字段值'creditCard'为false。
收到的结果是Firestore拒绝了读取权限(尽管“creditCard”字段值为false)。有谁能解释一下原因,并提供一个解决方案?
请注意,父集合“users”、“userA”和“userB”除了确认持有子集合的文档的iD的单个值之外是空的,并且“exclusiveB”文档具有确认当前用户的uid的字段和确认文档的iD的另一个字段。
Firestore地层的照片如下:

安全规则包括:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {  
  
  match /users {
      // if a rule isn't specified, Firestore denies by default
        allow read;
  }
  
  match /users/{docId}/userA {
        allow read;
  }
  
  match /users/{docId}/userB {
        allow read;
  }
  
  match /users/{docId}/userA/{docId2}/exclusiveA/{docId3} {
  
    // allow read if user: (1) has a uid, (2) has creditcard = false
        allow get: if request.auth.uid != null && get(/databases/$(database)/documents/users/{docId}/userB/{docIdB}/exclusiveB/$(request.auth.uid)).data.creditCard == false;
  }
  
  match /users/{docId}/userB/{docId2}/exclusiveB/{xcluB} {
        allow get: if resource.data.uid == request.auth.uid;
  }
  
  match /users/{docId}/userA/{docId2}/otherDetails/{id} {
        allow read: if request.auth.uid == resource.data.id;
  }
  
  match /users/{docId}/userB/{docId2}/otherDetails/{id} {
        allow read: if request.auth.uid == resource.data.id;
  }

  }

}

Firestore查询在用户界面级别的Flutter代码是:

import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart' as auth;
import 'package:cloud_firestore/cloud_firestore.dart';

class StreamResults extends StatefulWidget {
  @override
  State<StreamResults> createState() => _StreamResultsState();
}

class _StreamResultsState extends State<StreamResults> {
  final _auth = auth.FirebaseAuth.instance;
  final _dB = FirebaseFirestore.instance;
  final _dataSource = FirebaseFirestore.instance
      .collection(
          'users/l9NzQFjN4iB0JlJaY3AI/userA/2VzSHur3RllcF5PojT61/exclusiveA');

  String? vehicleMake, vehicleTitle, currentUserID, pCurrency, currency, uid, docRefID;
  int? maxSpeed, pullStrength;

  void getIdentity() {
    currentUserID = _auth.currentUser!.uid;
    print('The current user\'s ID is: $currentUserID.');
  }
  
  Future<void> matchDetails() async {
    final exclusiveBcollection = await _dB.collection('users/l9NzQFjN4iB0JlJaY3AI/userB/mv6YgmAfIDEkUNmstrzg/exclusiveB')
        .where('uid', isEqualTo: currentUserID).get().then((QuerySnapshot querySnapshot) {
          querySnapshot.docs.forEach((doc) {
            currency = doc['currency'];
            uid = doc['uid'];
            docRefID = doc['docRefID'];
          });
    });
  }

  @override
  void initState() {
    getIdentity();
    matchDetails();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<QuerySnapshot>(
        stream: _dataSource.where('preferredCurrency', isEqualTo: currency).snapshots().distinct(),
        builder: (context, snapshot) {
          if (!snapshot.hasData) {
            CircularProgressIndicator();
          } else if (snapshot.hasData) {
            final retrievedData = snapshot.data!.docs;
            for (var specific in retrievedData) {
              maxSpeed = specific['topSpeed'];
              vehicleTitle = specific['vehicleName'];
              pullStrength = specific['horsePower'];
              vehicleMake = specific['vehicleBrand'];
              pCurrency = specific['preferredCurrency'];
              print('The vehicle\'s maximum speed = $maxSpeed.');
              print('The vehicle\'s pulling strength = $pullStrength bph.');
              print(
                  'The vehicle\'s brand is $vehicleMake, and its model-name is $vehicleTitle.');
              print('The preferred currency = $pCurrency.');
            }
          }
          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.'),
            ],
          );
        });
  }
}

谢谢

tcomlyy6

tcomlyy61#

此查询:

final _dataSource = FirebaseFirestore.instance
      .collection(
          'users/l9NzQFjN4iB0JlJaY3AI/userA/2VzSHur3RllcF5PojT61/exclusiveA');

  _dataSource.where('preferredCurrency', isEqualTo: currency).snapshots().distinct(),

这个查询:

final exclusiveBcollection = await _dB.collection('users/l9NzQFjN4iB0JlJaY3AI/userB/mv6YgmAfIDEkUNmstrzg/exclusiveB')
        .where('uid', isEqualTo: currentUserID).get().then((QuerySnapshot querySnapshot) {

从安全规则的Angular 来看,两者都试图将list文档化的子集合。但您的规则只允许单个文档get操作:

match /users/{docId}/userA/{docId2}/exclusiveA/{docId3} {
        allow get: if request.auth.uid != null && get(/databases/$(database)/documents/users/{docId}/userB/{docIdB}/exclusiveB/$(request.auth.uid)).data.creditCard == false;
  }
  
  match /users/{docId}/userB/{docId2}/exclusiveB/{xcluB} {
        allow get: if resource.data.uid == request.auth.uid;
  }

如果你想查询(list)一个集合,你需要添加这个权限。您可以通过指定list或仅使用readgetlist的组合)来实现这一点,如文档中所述。

match /users/{docId}/userA/{docId2}/exclusiveA/{docId3} {
        allow read: if request.auth.uid != null && get(/databases/$(database)/documents/users/{docId}/userB/{docIdB}/exclusiveB/$(request.auth.uid)).data.creditCard == false;
  }
  
  match /users/{docId}/userB/{docId2}/exclusiveB/{xcluB} {
        allow read: if resource.data.uid == request.auth.uid;
  }

相关问题