У меня есть приложение 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, для вступления в силу изменений правил может потребоваться до минуты.)
Вопросы:
Я не должен получать какие-то указание на отказ в доступе? В этом примере приложения это неплохо, но в моем реальном приложении у меня нет возможности узнать, что я должен как-то отреагировать и направить пользователя на вход или что-то еще. Я просто никогда не получаю никаких ошибок, а приложение просто сидит, показывая индикатор загрузки. Я действительно вижу, что число «всего отказов» увеличивается в представлении «Правила мониторинга» в консоли Firebase. Правило также не работает на игровой площадке, когда я тестирую вызов без аутентификации.
Почему приложение продолжает получать данные даже после изменения правила? Зачем его удалять?
Что я делаю не так?