firestoreのセキュリティルール
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /{document=**} { allow read, write: if request.time < timestamp.date(2023, 10, 3); } } }
認証されたユーザのみ許可に変更
match /{document=**} { allow read, write: if request.auth != null && request.auth.uid != null; }
### Authenticationによるユーザ認証
FirebaseのauthenticationでGoogleを許可する
$ flutter pub add firebase_auth
$ flutter pub upgrade firebase_auth
$ flutter pub add google_sign_in
$ flutter pub upgrade google_sign_in
import 'package:flutter/material.dart'; import 'dart:ui' as ui; import 'dart:convert'; import 'dart:io'; import 'package:firebase_core/firebase_core.dart'; import 'firebase_options.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:google_sign_in/google_sign_in.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform, ); runApp(new MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return new MaterialApp( title: 'Generated App', theme: new ThemeData( primarySwatch: Colors.blue, primaryColor: const Color(0xFF2196f3), canvasColor: const Color(0xFFfafafa), ), home: MyHomePage(), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key? key}) : super(key: key); @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { final _controller = TextEditingController(); static const url = 'https://jsonplaceholder.typicode.com/posts'; @override void initState(){ super.initState(); fire(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Home'), ), body: Padding( padding: EdgeInsets.all(20.0), child:Column( children:<Widget> [ Text('INTERNET ACCESS', style: TextStyle(fontSize: 32, fontWeight: ui.FontWeight.w500), ), Padding(padding: EdgeInsets.all(10.0)), TextField( controller: _controller, style: TextStyle(fontSize: 24), minLines: 1, maxLines: 5, ), ], ), ), floatingActionButton: FloatingActionButton( child: Icon(Icons.open_in_new), onPressed: () { doSignin(); } ) ); } void addDoc() async { var msg = _controller.text; final input = msg.split(','); final data = { 'name': input[0], 'mail': input[1], 'age': input[2] }; FirebaseFirestore firestore = FirebaseFirestore.instance; final snapshot = await firestore.collection('mydata') .add(data); fire(); } void fire() async { var msg = ''; FirebaseFirestore firestore = FirebaseFirestore.instance; final snapshot = await firestore.collection('mydata') .orderBy('name', descending: false).get(); snapshot.docChanges.forEach((element) { final name = element.doc.get('name'); final mail = element.doc.get('mail'); final age = element.doc.get('age'); msg += "\n${name} (${age}) <${mail}>"; }); _controller.text = msg; } Future<UserCredential> signInWithGoogle() async { final GoogleSignInAccount? googleUser = await GoogleSignIn().signIn(); final GoogleSignInAuthentication? googleAuth = await googleUser?.authentication; final credential = GoogleAuthProvider.credential( accessToken: googleAuth?.accessToken, idToken: googleAuth?.idToken, ); return await FirebaseAuth.instance.signInWithCredential(credential); } void doSignin() { signInWithGoogle().then((value) { if(value.user != null) { fire(); } }); } }