Правила доступа Firestore не сообщают об ошибках, когда запрещают доступ - PullRequest
1 голос
/ 09 мая 2020

У меня есть приложение Flutter, использующее Firestore, Auth еще не используется, т.е. приложение попытается получить доступ без аутентификации. Кажется, все настроено правильно, так как в целом работает как на Android, так и на iOS - я могу получить eata. Я просто вижу какое-то странное поведение, когда я меняю правило доступа на одно, которое должно приводить к «доступу отказано».

Боковое примечание: проект Firebase фактически настроен на использование Firebase Auth с Google Sign In, и он работает в реальном приложении, я просто полностью удалил код для этого, чтобы проверить странное поведение.

Приложение:

import 'dart:async';

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

void main() {
  runApp(
    MaterialApp(
      title: 'Test',
      home: Screen(),
    ),
  );
}

class Screen extends StatefulWidget {
  @override
  _ScreenState createState() => _ScreenState();
}

class _ScreenState extends State<Screen> {
  StreamSubscription<dynamic> _sub;

  @override
  void initState() {
    super.initState();
    _initAsync();
  }

  Future<void> _initAsync() async {
    final user = await FirebaseAuth.instance.currentUser();
    print('>>> currentUser.uid: ${user?.uid}');
    print('will start listening');
    _sub = Firestore.instance.collection('categories').snapshots().listen(
        (querySnapshot) {
      print('>>> got data: $querySnapshot');
      querySnapshot.documents.forEach((documentSnapshot) {
        print('>>> ${documentSnapshot.data['name']}');
      });
    }, onError: (error) {
      print('!!! got error: $error');
    });
  }

  @override
  void dispose() {
    _sub?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

Со следующим правилом:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write;
    }
  }
}

работает, данные получаю. Однако, когда я меняю правило на:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if request.auth != null;
    }
  }
}

Результат (начиная с недавно сброшенного симулятора):

flutter: >>> currentUser.uid: null
flutter: will start listening

, тогда он просто ничего не делает, никаких ошибок не возникает.

Странная вещь # 1 : по какой-то причине мне нужно удалить приложение и установить его снова, иначе я все еще могу получить данные (я использую симулятор iOS).

Изменить : как объясняет ниже Фрэнк, это связано с кешем из предыдущих запусков приложения. Мне удалось отключить кеш с помощью этого кода:

await Firestore.instance.settings(persistenceEnabled: false);

, и теперь данные не отображаются, как я ожидал с самого начала. (Я не рекомендую отключать кеш, это просто для понимания.)

Странная вещь # 2 : когда я удаляю и снова устанавливаю приложение, я не получаю данных, но и тоже Я получаю любую ошибку типа «доступ запрещен», чего и ожидал. Приложение подписывается, а затем ничего не происходит, из потока ничего не возвращается.

Изменить : следующий код приводит к ошибке:

Firestore.instance.collection('categories').getDocuments().asStream().listen(...)

но это просто приводит к единственному событию, так как конвертирует будущее. В Firestore есть журнал ошибок, связанных с ошибками, основная проблема здесь: https://github.com/FirebaseExtended/flutterfire/issues/1223, и более конкретные c проблемы для моего случая: https://github.com/FirebaseExtended/flutterfire/issues/2334 и https://github.com/FirebaseExtended/flutterfire/issues/1465. Опять же, Фрэнк ниже обнаружил проблемы.

Странная вещь # 3 : когда я изменяю правило, чтобы снова разрешить весь доступ и снова запустить приложение, все снова работает, я не необходимо удалить и снова установить приложение.

Изменить : это снова можно объяснить кешем / сохраняемостью.

(Я немного подождал между проверками как сказала мне консоль Firebase, для вступления в силу изменений правил может потребоваться до минуты.)

Вопросы:

  1. Я не должен получать какие-то указание на отказ в доступе? В этом примере приложения это неплохо, но в моем реальном приложении у меня нет возможности узнать, что я должен как-то отреагировать и направить пользователя на вход или что-то еще. Я просто никогда не получаю никаких ошибок, а приложение просто сидит, показывая индикатор загрузки. Я действительно вижу, что число «всего отказов» увеличивается в представлении «Правила мониторинга» в консоли Firebase. Правило также не работает на игровой площадке, когда я тестирую вызов без аутентификации.

  2. Почему приложение продолжает получать данные даже после изменения правила? Зачем его удалять?

Что я делаю не так?

1 Ответ

1 голос
/ 09 мая 2020

Клиент Firestore кэширует любые данные, которые он видит в кэше локального диска, так что он может показать эти данные быстрее при следующем запросе. В этом локальном кэше диска правила безопасности вашей базы данных не применяются (так как это все равно не поможет).

Итак, причина, по которой вам нужно удалить / переустановить приложение, - это избавиться от данных в дисковый кеш. Обычно эта проблема возникает только во время разработки правил безопасности, что является одной из причин, по которой вам следует сделать это перед отправкой приложения обычным пользователям.


Если операция чтения не разрешена из-за правила безопасности, ваш onError будет вызван и в вашем случае распечатает сообщение. Обычно вы хотите установить здесь сообщение об ошибке и отобразить его.

Обратите внимание, что возможно (в вашем случае здесь), что основной обратный вызов для listen запускается с данными из кеша , и что чуть позже onError срабатывает с отклонением от сервера.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...