【问题标题】:Firestore security rules: why can I read the data?Firestore 安全规则:为什么我可以读取数据?
【发布时间】:2020-12-30 07:25:27
【问题描述】:

我有一个名为 myusers 的 firestore 集合,其中包含大约 200 个包含用户信息的文档,例如电子邮件、姓名等。文档 ID 是 firebase uid。

我设置了以下安全规则

    rules_version = '2';
    service cloud.firestore {
      match /databases/{database}/documents {
        
        function isRestaurant() {
            return request.auth.uid == 'agivenuser' || request.auth.uid == 'anothergivenuser';
          }
    
        match /myusers/{user} {
          allow read: if resource.data.userId == request.auth.uid || isRestaurant();
          allow create: if request.auth.uid != null;
            
            match /mytok/{doc}/{document=**} {
                allow read: if request.auth.uid == user || isRestaurant();
                allow create: if request.resource.data.userId == request.auth.uid;
            }   
        }
      }

现在我尝试使用不使 isRestaurant() 为 true 的用户登录,并且看起来该用户可以访问整个 myusers 集合。我认为resource.data.userId == request.auth.uid 基本上会让用户只看到他的 uid 与给定文档的 userId 字段匹配的文档。实际上,他可以看到整个集合以及其中的所有文档。

请注意,当我尝试使用 getDocuments() 读取集合时,我无法读取任何文档,但如果我创建一个流,看起来我可以读取所有内容。

这是我获取文档的代码(无法读取集合)

  void check() async {    
    final QuerySnapshot result = await Firestore.instance.collection('myusers').getDocuments();
    final List<DocumentSnapshot> documents = result.documents;
    documents.forEach((element) {
      print(element['email']);
    });

这是带有 StreamBuilder 的代码(它让我打印集合中每个文档的所有电子邮件)

    Stream myStream;
    @override
    void initState() {
      super.initState();
      myStream = _firestore.collection('myusers').snapshots();
    }

              SliverList(
                delegate: SliverChildListDelegate([
                  StreamBuilder<QuerySnapshot>(
                    stream: myStream,
                    builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
                      if (snapshot.hasError) return new Text('Error: ${snapshot.error}');
                      switch (snapshot.connectionState) {
                        case ConnectionState.waiting:
                          return new Text(
                            'Loading...',
                            style: kSendButtonTextStyle.copyWith(color: kColorText),
                          );
                        default:
                          customerDB = snapshot.data.documents;
                          snapshot.data.documents.forEach((element) {
                            print(element['email']);
                          });
                          return new ListView(
                            shrinkWrap: true,
                            physics: ClampingScrollPhysics(),
                            children: customerDB.map((DocumentSnapshot document) {
                              return Padding(
                                padding: const EdgeInsets.symmetric(horizontal: 8.0),
                                child: Card(
                                  color: kColorPrimaryLight,
                                  child: ListTile(
                                    title: Text(
                                      (document['userName'] ?? 'xxx'), 
                                  ),
                                ),
                              );
                            }).toList(),
                          );
                      }
                    },
                  )
                ]),
              ),

我做错了什么?

【问题讨论】:

  • "实际上任何用户都可以看到 entore 集合以及其中的所有文档。" - 您是如何得出这个结论的?你做了什么来证明这一点?请编辑问题以充分解释。
  • 嗨,Doug,我添加了更多上下文。看起来,作为用户,我能够阅读整个集合,而不仅仅是集合中 userId = 到 uid 的文档
  • 您的代码使用了一个名为“myuser”的集合,但您的规则说的是“myusers”。
  • 错字已更正,谢谢
  • 嗨,Doug,您看到我的代码中有任何错误吗?给定用户可以访问集合“myusers”中的所有文档,而我希望他只能访问他的文档(= 字段“userId”等于 uid 的那个)

标签: firebase google-cloud-firestore firebase-security


【解决方案1】:

使用这样的东西:

match /users/{userId} {
  allow create: if request.auth != null;
  allow read, update, delete: if request.auth.uid == userId;
}

这将允许任何经过身份验证的用户创建新数据,但只有拥有该文档的用户才能修改该文档。

【讨论】:

  • 我已经使用了您建议的代码,但我一直遇到同样的问题(我的集合称为 myusers)。如果我以用户身份登录,我可以阅读整个用户集合。如果我使用流构建器,我可以读取数据。如果我使用 Firestore.instance.collection('myusers').getDocuments();,它不允许我读取用户集合
  • 不可能。那你做错了什么。上面的这条规则将只允许创建文档的用户修改该文档,但您需要确保文档 ID 与用户 ID 相同
  • 我同意我做错了什么,但我不知道是什么。现实情况是,当我在模拟器中运行应用程序时,我实际上能够阅读整个集合,即任何用户都可以阅读所有用户的电子邮件。我对此感到震惊,我不确定这怎么可能。你认为什么能让它发生?我已经用上面的流构建器添加了我的颤振代码
【解决方案2】:

任何匹配resource.data.userId == request.auth.uid OR isRestaurant() 的用户都可以读取资源。

请确认您没有使用使 isRestaurant 评估为 true 的用户。

【讨论】:

  • 您好,是的,我没有使用使 isRestaurant 为真的用户
  • 您好,我已经添加了一些附加信息。我真的很震惊,一个简单的用户可以读取我在该集合中的所有数据。我的目的是让 isRestaurant() 中的用户访问所有数据,但限制所有其他人只能看到 1 个文档,即他自己的文档
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-11
  • 2021-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-19
相关资源
最近更新 更多