Codelab su Firebase Angular Web Framework

1. Che cosa creerai

In questo codelab, creerai un blog itinerante con una mappa collaborativa in tempo reale con le ultime novità della nostra libreria Angular: AngularFire. L'app web finale consisterà in un blog di viaggi in cui potrai caricare immagini in ogni località che hai visitato.

AngularFire verrà utilizzato per creare l'app web, Emulator Suite per i test locali, Authentication per tenere traccia dei dati utente, Firestore e Storage per mantenere dati e contenuti multimediali basati su Cloud Functions e, infine, Firebase Hosting per il deployment dell'app.

Obiettivi didattici

  • Come sviluppare localmente con i prodotti Firebase con Emulator Suite
  • Come migliorare la tua app web con AngularFire
  • Come rendere persistenti i dati in Firestore
  • Come conservare i contenuti multimediali in Storage
  • Come eseguire il deployment dell'app su Firebase Hosting
  • Come utilizzare Cloud Functions per interagire con i database e le API

Che cosa ti serve

  • Node.js versione 10 o successive
  • Un Account Google per la creazione e la gestione di un progetto Firebase
  • L'interfaccia a riga di comando di Firebase 11.14.2 o versioni successive
  • Un browser a tua scelta, ad esempio Chrome
  • Conoscenza di base di Angular e JavaScript

2. recupera il codice campione

Clona il repository GitHub del codelab dalla riga di comando:

git clone https://github.com/firebase/codelab-friendlychat-web

In alternativa, se non hai installato Git, puoi scaricare il repository come file ZIP.

Il repository GitHub contiene progetti di esempio per più piattaforme.

Questo codelab utilizza solo il repository di framework web:

  • 📁 webframework: il codice iniziale su cui lavorerai durante questo codelab.

Installa le dipendenze

Dopo la clonazione, installa le dipendenze nella cartella principale e nella cartella functions prima di creare l'app web.

cd webframework && npm install
cd functions && npm install

Installa l'interfaccia a riga di comando di Firebase

Installa l'interfaccia a riga di comando di Firebase utilizzando questo comando in un terminale:

npm install -g firebase-tools

Verifica che la versione dell'interfaccia a riga di comando di Firebase sia successiva alla 11.14.2 utilizzando:

firebase  --version

Se la tua versione è precedente alla 11.14.2, esegui l'aggiornamento utilizzando:

npm update firebase-tools

3. Crea e configura un progetto Firebase

Creare un progetto Firebase

  1. Accedi a Firebase.
  2. Nella Console Firebase, fai clic su Aggiungi progetto e poi assegna un nome al progetto Firebase, ad esempio <your-project>. Ricorda l'ID progetto Firebase.
  3. Fai clic su Crea progetto.

Importante: il progetto Firebase avrà il nome <your-project>, ma Firebase gli assegnerà automaticamente un ID progetto univoco nel formato <your-project>-1234. Questo identificatore univoco è il modo in cui viene identificato il progetto (anche nella CLI), mentre <your-project> è semplicemente un nome visualizzato.

L'applicazione che stiamo per creare utilizza i prodotti Firebase disponibili per le app web:

  • Firebase Authentication per consentire agli utenti di accedere facilmente alla tua app.
  • Cloud Firestore per salvare i dati strutturati sul cloud e ricevere notifiche immediate quando i dati subiscono modifiche.
  • Cloud Storage for Firebase per salvare i file nel cloud.
  • Firebase Hosting per ospitare e pubblicare i tuoi asset.
  • Funzioni per interagire con API interne ed esterne.

Alcuni di questi prodotti richiedono configurazioni speciali o devono essere attivati utilizzando la console Firebase.

Aggiungi un'app web Firebase al progetto

  1. Fai clic sull'icona web per creare una nuova app web Firebase.
  2. Nel passaggio successivo, visualizzerai un oggetto di configurazione. Copia i contenuti di questo oggetto nel file environments/environment.ts.

Attivare l'accesso con Google per Firebase Authentication

Per consentire agli utenti di accedere all'app web con i propri Account Google, utilizzeremo il metodo di accesso di Google.

Per attivare l'accesso con Google:

  1. Nella Console Firebase, individua la sezione Crea nel riquadro di sinistra.
  2. Fai clic su Autenticazione, quindi sulla scheda Metodo di accesso (o fai clic qui per andare direttamente a questa pagina).
  3. Attiva il provider di accesso a Google e fai clic su Salva.
  4. Imposta il nome visibile al pubblico della tua app su <nome-del-tuo-progetto> e scegli un'email di assistenza per il progetto dal menu a discesa.

Abilita Cloud Firestore

  1. Nella sezione Build della console Firebase, fai clic su Database Firestore.
  2. Fai clic su Crea database nel riquadro Cloud Firestore.
  3. Imposta la posizione in cui sono archiviati i dati di Cloud Firestore. Puoi lasciare questa impostazione predefinita o scegliere una regione vicina a te.

Abilitare Cloud Storage

L'app web utilizza Cloud Storage for Firebase per archiviare, caricare e condividere le immagini.

  1. Nella sezione Build della console Firebase, fai clic su Archiviazione.
  2. Se non visualizzi il pulsante Inizia, significa che Cloud Storage è già

abilitata e non devi seguire i passaggi riportati di seguito.

  1. Fai clic su Inizia.
  2. Leggi il disclaimer relativo alle regole di sicurezza per il tuo progetto Firebase, quindi fai clic su Avanti.
  3. La posizione di Cloud Storage è preselezionata con la stessa regione scelta per il database Cloud Firestore. Fai clic su Fine per completare la configurazione.

Con le regole di sicurezza predefinite, qualsiasi utente autenticato può scrivere qualsiasi cosa in Cloud Storage. Renderemo il nostro spazio di archiviazione più sicuro più avanti in questo codelab.

4. Connettersi al progetto Firebase

L'interfaccia a riga di comando (CLI) di Firebase ti consente di utilizzare Firebase Hosting per pubblicare la tua app web localmente, nonché di eseguire il deployment della tua app web nel tuo progetto Firebase.

Assicurati che la riga di comando acceda alla directory webframework locale dell'app.

Collega il codice dell'app web al tuo progetto Firebase. Per prima cosa, accedi all'interfaccia a riga di comando di Firebase dalla riga di comando:

firebase login

Quindi, esegui il comando seguente per creare un alias del progetto. Sostituisci $YOUR_PROJECT_ID con l'ID del tuo progetto Firebase.

firebase  use  $YOUR_PROJECT_ID

Aggiungi AngularFire

Per aggiungere AngularFire all'app, esegui il comando:

ng add @angular/fire

Quindi, segui le istruzioni della riga di comando e seleziona le funzionalità esistenti nel progetto Firebase.

Inizializza Firebase

Per inizializzare il progetto Firebase, esegui:

firebase init

Quindi, seguendo le istruzioni della riga di comando, seleziona le funzionalità e gli emulatori utilizzati nel progetto Firebase.

Avvia gli emulatori

Dalla directory webframework, esegui il seguente comando per avviare gli emulatori:

firebase  emulators:start

Dovresti vedere qualcosa di simile a questo:

$  firebase  emulators:start

i  emulators:  Starting  emulators:  auth,  functions,  firestore,  hosting,  functions

i  firestore:  Firestore  Emulator  logging  to  firestore-debug.log

i  hosting:  Serving  hosting  files  from:  public

  hosting:  Local  server:  http://localhost:5000

i  ui:  Emulator  UI  logging  to  ui-debug.log

i  functions:  Watching  "/functions"  for  Cloud  Functions...

  functions[updateMap]:  firestore  function  initialized.

  

┌─────────────────────────────────────────────────────────────┐

    All  emulators  ready!  It  is  now  safe  to  connect  your  app.  

  i  View  Emulator  UI  at  http://localhost:4000  

└─────────────────────────────────────────────────────────────┘

  

┌────────────────┬────────────────┬─────────────────────────────────┐

  Emulator    Host:Port    View  in  Emulator  UI  

├────────────────┼────────────────┼─────────────────────────────────┤

  Authentication    localhost:9099    http://localhost:4000/auth  

├────────────────┼────────────────┼─────────────────────────────────┤

  Functions    localhost:5001    http://localhost:4000/functions  

├────────────────┼────────────────┼─────────────────────────────────┤

  Firestore    localhost:8080    http://localhost:4000/firestore  

├────────────────┼────────────────┼─────────────────────────────────┤

  Hosting    localhost:5000    n/a  

└────────────────┴────────────────┴─────────────────────────────────┘

Emulator  Hub  running  at  localhost:4400

Other  reserved  ports:  4500

  

Issues?  Report  them  at  https://github.com/firebase/firebase-tools/issues  and  attach  the  *-debug.log  files.

Quando viene visualizzato il messaggio ✔All emulators ready!, gli emulatori sono pronti per l'uso.

Dovresti vedere l'UI della tua app di viaggi, che non funziona (ancora!):

Ora iniziamo a creare.

5. Collega l'app web agli emulatori

In base alla tabella nei log dell'emulatore, l'emulatore Cloud Firestore è in ascolto sulla porta 8080 e l'emulatore Authentication è in ascolto sulla porta 9099.

Apri EmulatorUI

Nel browser web, vai all'indirizzo http://127.0.0.1:4000/. Dovresti vedere l'interfaccia utente di Emulator Suite.

Indirizza l'app a utilizzare gli emulatori

In src/app/app.module.ts, aggiungi il seguente codice all'elenco di importazioni di AppModule:

@NgModule({
	declarations: [...],
	imports: [
		provideFirebaseApp(() =>  initializeApp(environment.firebase)),

		provideAuth(() => {
			const  auth = getAuth();
			if (location.hostname === 'localhost') {
				connectAuthEmulator(auth, 'http://127.0.0.1:9099', { disableWarnings:  true });
			}
			return  auth;
		}),

		provideFirestore(() => {
			const  firestore = getFirestore();
			if (location.hostname === 'localhost') {
				connectFirestoreEmulator(firestore, '127.0.0.1', 8080);
			}
			return  firestore;
		}),

		provideFunctions(() => {
			const  functions = getFunctions();
			if (location.hostname === 'localhost') {
				connectFunctionsEmulator(functions, '127.0.0.1', 5001);
			}
			return  functions;
		}),

		provideStorage(() => {
			const  storage = getStorage();
			if (location.hostname === 'localhost') {
				connectStorageEmulator(storage, '127.0.0.1', 5001);
			}
			return  storage;
		}),
		...
	]

L'app è ora configurata per utilizzare emulatori locali, il che consente di eseguire test e sviluppo localmente.

6. Aggiunta dell'autenticazione

Ora che gli emulatori sono configurati per l'app, possiamo aggiungere funzionalità di autenticazione per assicurarci che ogni utente abbia eseguito l'accesso prima di pubblicare i messaggi.

Per farlo, possiamo importare le funzioni signin direttamente da AngularFire e monitorare lo stato di autenticazione dell'utente con la funzione authState. Modifica le funzioni della pagina di accesso in modo che la pagina controlli lo stato di autenticazione dell'utente al caricamento.

Iniezione dell'autenticazione AngularFire

In src/app/pages/login-page/login-page.component.ts, importa Auth da @angular/fire/auth e inseriscilo in LoginPageComponent. Anche i provider di autenticazione, come Google, e funzioni come signin e signout possono essere importati direttamente dallo stesso pacchetto e utilizzati nell'app.

import { Auth, GoogleAuthProvider, signInWithPopup, signOut, user } from  '@angular/fire/auth';

export  class  LoginPageComponent  implements  OnInit {
	private  auth: Auth = inject(Auth);
	private  provider = new  GoogleAuthProvider();
	user$ = user(this.auth);
	constructor() {}  

	ngOnInit(): void {} 

	login() {
		signInWithPopup(this.auth, this.provider).then((result) => {
			const  credential = GoogleAuthProvider.credentialFromResult(result);
			return  credential;
		})
	}

	logout() {
		signOut(this.auth).then(() => {
			console.log('signed out');}).catch((error) => {
				console.log('sign out error: ' + error);
		})
	}
}

La pagina di accesso è ora funzionale. Prova ad accedere e controlla i risultati nell'Emulatore di autenticazione.

7. Configurazione di Firestore

In questo passaggio, aggiungerai funzionalità per pubblicare e aggiornare i post del blog di viaggi archiviati in Firestore.

Analogamente all'autenticazione, le funzioni Firestore sono preconfezionate da AngularFire. Ogni documento appartiene a una raccolta e ogni documento può anche avere raccolte nidificate. Per creare e aggiornare un post del blog di viaggi è necessario conoscere il path del documento in Firestore.

Implementazione di TravelService

Poiché molte pagine diverse dovranno leggere e aggiornare i documenti Firestore nell'app web, possiamo implementare le funzioni in src/app/services/travel.service.ts, per evitare di inserire ripetutamente le stesse funzioni AngularFire ogni pagina.

Inizia inserendo Auth, come nel passaggio precedente, nonché Firestore nel nostro servizio. Anche la definizione di un oggetto user$ osservabile che ascolti lo stato attuale dell'autenticazione è utile.

import { doc, docData, DocumentReference, Firestore, getDoc, setDoc, updateDoc, collection, addDoc, deleteDoc, collectionData, Timestamp } from  "@angular/fire/firestore";

export  class  TravelService {
	firestore: Firestore = inject(Firestore);
	auth: Auth = inject(Auth);
	user$ = authState(this.auth).pipe(filter(user  =>  user !== null), map(user  =>  user!));
	router: Router = inject(Router);

Aggiunta di un post di viaggio

I post di viaggio esistono come documenti archiviati in Firestore e, poiché i documenti devono esistere all'interno di raccolte, la raccolta che contiene tutti i post di viaggio sarà denominata travels. Pertanto, il percorso di qualsiasi post di viaggio sarà travels/

Utilizzando la funzione addDoc di AngularFire, è possibile inserire un oggetto in una raccolta:

async  addEmptyTravel(userId: String) {
	...
	addDoc(collection(this.firestore, 'travels'), travelData).then((travelRef) => {
		collection(this.firestore, `travels/${travelRef.id}/stops`);
		setDoc(travelRef, {... travelData, id:  travelRef.id})
		this.router.navigate(['edit', `${travelRef.id}`]);
		return  travelRef;

	})
}

Aggiornamento ed eliminazione dei dati

Dato l'uid di qualsiasi post di viaggio, si può dedurre il percorso del documento archiviato in Firestore, che può quindi essere letto, aggiornato o eliminato utilizzando le funzioni updateFoc e deleteDoc di AngularFire:

async  updateData(path: string, data: Partial<Travel | Stop>) {
	await  updateDoc(doc(this.firestore, path), data)
}

async  deleteData(path: string) {
	const  ref = doc(this.firestore, path);
	await  deleteDoc(ref)
}

Lettura dei dati come osservabili

Poiché i post e le fermate lungo il percorso possono essere modificati dopo la creazione, sarebbe più utile ottenere gli oggetti documento come osservabili, per abbonarsi a qualsiasi modifica apportata. Questa funzionalità è offerta dalle funzioni docData e collectionData di @angular/fire/firestore.

getDocData(path: string) {
	return  docData(doc(this.firestore, path), {idField:  'id'}) as  Observable<Travel | Stop>
}

  
getCollectionData(path: string) {
	return  collectionData(collection(this.firestore, path), {idField:  'id'}) as  Observable<Travel[] | Stop[]>
}

Aggiungere fermate a un post di viaggio

Ora che le operazioni dei post di viaggio sono configurate, è il momento di considerare le fermate, che esisteranno in una sottoraccolta di un post di viaggio come segue: travels//stops/

Questa operazione è quasi identica alla creazione di un post di viaggio, quindi mettiti alla prova e prova a implementarla autonomamente oppure dai un'occhiata all'implementazione riportata di seguito:

async  addStop(travelId: string) {
	...
	const  ref = await  addDoc(collection(this.firestore, `travels/${travelId}/stops`), stopData)
	setDoc(ref, {...stopData, id:  ref.id})
}

Bene! Le funzioni Firestore sono state implementate nel servizio Travel, quindi ora puoi vederle in azione.

Utilizzare le funzioni Firestore nell'app

Vai a src/app/pages/my-travels/my-travels.component.ts e inserisci TravelService per utilizzare le relative funzioni.

travelService = inject(TravelService);
travelsData$: Observable<Travel[]>;
stopsList$!: Observable<Stop[]>;
constructor() {
	this.travelsData$ = this.travelService.getCollectionData(`travels`) as  Observable<Travel[]>
}

TravelService viene chiamato nel costruttore per ottenere un array osservabile di tutti gli spostamenti.

Se sono necessari solo i viaggi dell'utente corrente, utilizza la funzione query.

Altri metodi per garantire la sicurezza includono l'implementazione di regole di sicurezza o l'utilizzo di Cloud Functions con Firestore, come descritto nei passaggi facoltativi riportati di seguito

Quindi, richiama semplicemente le funzioni implementate in TravelService.

async  createTravel(userId: String) {
	this.travelService.addEmptyTravel(userId);
}

deleteTravel(travelId: String) {
	this.travelService.deleteData(`travels/${travelId}`)
}

La pagina I miei viaggi dovrebbe essere funzionale. Scopri cosa succede nell'emulatore Firestore quando crei un nuovo post di viaggio.

Poi, ripeti l'operazione per le funzioni di aggiornamento in /src/app/pages/edit-travels/edit-travels.component.ts :

travelService: TravelService = inject(TravelService)
travelId = this.activatedRoute.snapshot.paramMap.get('travelId');
travelData$: Observable<Travel>;
stopsData$: Observable<Stop[]>;

constructor() {
	this.travelData$ = this.travelService.getDocData(`travels/${this.travelId}`) as  Observable<Travel>
	this.stopsData$ = this.travelService.getCollectionData(`travels/${this.travelId}/stops`) as  Observable<Stop[]>
}

updateCurrentTravel(travel: Partial<Travel>) {
	this.travelService.updateData(`travels${this.travelId}`, travel)
}

  

updateCurrentStop(stop: Partial<Stop>) {
	stop.type = stop.type?.toString();
	this.travelService.updateData(`travels${this.travelId}/stops/${stop.id}`, stop)
}

  

addStop() {
	if (!this.travelId) return;
	this.travelService.addStop(this.travelId);
}

deleteStop(stopId: string) {
	if (!this.travelId || !stopId) {
		return;
	}
	this.travelService.deleteData(`travels${this.travelId}/stops/${stopId}`)
	this.stopsData$ = this.travelService.getCollectionData(`travels${this.travelId}/stops`) as  Observable<Stop[]>

}

8. Configurazione dello spazio di archiviazione

Ora devi implementare Storage per archiviare immagini e altri tipi di contenuti multimediali.

Cloud Firestore è ideale per archiviare dati strutturati, come oggetti JSON. Cloud Storage è progettato per archiviare file o blob. In questa app, la utilizzerai per consentire agli utenti di condividere le foto dei loro viaggi.

Analogamente a Firestore, l'archiviazione e l'aggiornamento dei file con Storage richiede un identificatore univoco per ogni file.

Implementiamo le funzioni in TraveService:

Caricamento di un file

Vai a src/app/services/travel.service.ts e inietta Storage da AngularFire:

export  class  TravelService {
firestore: Firestore = inject(Firestore);
auth: Auth = inject(Auth);
storage: Storage = inject(Storage);

Implementa la funzione di caricamento:

async  uploadToStorage(path: string, input: HTMLInputElement, contentType: any) {
	if (!input.files) return  null
	const  files: FileList = input.files;
		for (let  i = 0; i  <  files.length; i++) {
			const  file = files.item(i);
			if (file) {
				const  imagePath = `${path}/${file.name}`
				const  storageRef = ref(this.storage, imagePath);
				await  uploadBytesResumable(storageRef, file, contentType);
				return  await  getDownloadURL(storageRef);
			}
		}
	return  null;
}

La differenza principale tra l'accesso ai documenti da Firestore e ai file da Cloud Storage è che, sebbene entrambi seguano percorsi strutturati delle cartelle, la combinazione di URL di base e percorso viene ottenuta tramite getDownloadURL, che può essere archiviata e utilizzata in un file .

Utilizzare la funzione nell'app

Vai a src/app/components/edit-stop/edit-stop.component.ts e chiama la funzione di caricamento utilizzando:

	async  uploadFile(file: HTMLInputElement, stop: Partial<Stop>) {
	const  path = `/travels/${this.travelId}/stops/${stop.id}`
	const  url = await  this.travelService.uploadToStorage(path, file, {contentType:  'image/png'});
	stop.image = url ? url : '';
	this.travelService.updateData(path, stop);
}

Una volta caricata l'immagine, il file multimediale stesso verrà caricato nello spazio di archiviazione e l'URL verrà archiviato di conseguenza nel documento in Firestore.

9. Implementazione dell'applicazione

Ora è tutto pronto per eseguire il deployment dell'applicazione.

Copia le configurazioni firebase da src/environments/environment.ts a src/environments/environment.prod.ts ed esegui:

firebase deploy

Il risultato dovrebbe essere simile a questo:

 Browser application bundle generation complete.
 Copying assets complete.
 Index html generation complete.

=== Deploying to 'friendly-travels-b6a4b'...

i  deploying storage, firestore, hosting
i  firebase.storage: checking storage.rules for compilation errors...
  firebase.storage: rules file storage.rules compiled successfully
i  firestore: reading indexes from firestore.indexes.json...
i  cloud.firestore: checking firestore.rules for compilation errors...
  cloud.firestore: rules file firestore.rules compiled successfully
i  storage: latest version of storage.rules already up to date, skipping upload...
i  firestore: deploying indexes...
i  firestore: latest version of firestore.rules already up to date, skipping upload...
  firestore: deployed indexes in firestore.indexes.json successfully for (default) database
i  hosting[friendly-travels-b6a4b]: beginning deploy...
i  hosting[friendly-travels-b6a4b]: found 6 files in .firebase/friendly-travels-b6a4b/hosting
  hosting[friendly-travels-b6a4b]: file upload complete
  storage: released rules storage.rules to firebase.storage
  firestore: released rules firestore.rules to cloud.firestore
i  hosting[friendly-travels-b6a4b]: finalizing version...
  hosting[friendly-travels-b6a4b]: version finalized
i  hosting[friendly-travels-b6a4b]: releasing new version...
  hosting[friendly-travels-b6a4b]: release complete

  Deploy complete!

Project Console: https://console.firebase.google.com/project/friendly-travels-b6a4b/overview
Hosting URL: https://friendly-travels-b6a4b.web.app

10. Complimenti!

Ora la tua applicazione dovrebbe essere completata e il cui deployment su Firebase Hosting è stato eseguito. Tutti i dati e le analisi saranno ora accessibili dalla console Firebase.

Per ulteriori funzionalità relative ad AngularFire, funzioni e regole di sicurezza, non dimenticare di dare un'occhiata ai passaggi facoltativi riportati di seguito e ad altri codelab di Firebase.

11. Facoltativo: protezioni di autenticazione AngularFire

Insieme a Firebase Authentication, AngularFire offre anche protezioni basate sull'autenticazione sulle route, in modo che gli utenti con accesso insufficiente possano essere reindirizzati. In questo modo, l'app è protetta dagli utenti che accedono ai dati protetti.

In src/app/app-routing.module.ts, importa

import {AuthGuard, redirectLoggedInTo, redirectUnauthorizedTo} from  '@angular/fire/auth-guard'

Puoi quindi definire le funzioni relative a quando e dove devono essere reindirizzati gli utenti in determinate pagine:

const  redirectUnauthorizedToLogin = () =>  redirectUnauthorizedTo(['signin']);
const  redirectLoggedInToTravels = () =>  redirectLoggedInTo(['my-travels']);

Poi aggiungili ai tuoi percorsi:

const  routes: Routes = [
	{path:  '', component:  LoginPageComponent, canActivate: [AuthGuard], data: {authGuardPipe:  redirectLoggedInToTravels}},
	{path:  'signin', component:  LoginPageComponent, canActivate: [AuthGuard], data: {authGuardPipe:  redirectLoggedInToTravels}},
	{path:  'my-travels', component:  MyTravelsComponent, canActivate: [AuthGuard], data: {authGuardPipe:  redirectUnauthorizedToLogin}},
	{path:  'edit/:travelId', component:  EditTravelsComponent, canActivate: [AuthGuard], data: {authGuardPipe:  redirectUnauthorizedToLogin}},
];

12. (Facoltativo) Regole di sicurezza

Sia Firestore che Cloud Storage utilizzano le regole di sicurezza (rispettivamente firestore.rules e security.rules) per applicare la sicurezza e convalidare i dati.

Al momento, i dati di Firestore e Storage hanno accesso libero per le operazioni di lettura e scrittura, ma non vuoi che gli utenti modifichino le impostazioni degli altri post! Puoi utilizzare le regole di sicurezza per limitare l'accesso alle tue raccolte e ai tuoi documenti.

Regole Firestore

Per consentire solo agli utenti autenticati di visualizzare i post sui viaggi, vai al file firestore.rules e aggiungi:

rules_version  =  '2';
service  cloud.firestore  {
	match  /databases/{database}/travels  {
		allow  read:  if  request.auth.uid  !=  null;
		allow  write:
		if  request.auth.uid  ==  request.resource.data.userId;
	}
}

Le regole di sicurezza possono essere utilizzate anche per convalidare i dati:

rules_version  =  '2';
service  cloud.firestore  {
	match  /databases/{database}/posts  {
		allow  read:  if  request.auth.uid  !=  null;
		allow  write:
		if  request.auth.uid  ==  request.resource.data.userId;
		&&  "author"  in  request.resource.data
		&&  "text"  in  request.resource.data
		&&  "timestamp"  in  request.resource.data;
	}
}

Regole di archiviazione

Analogamente, possiamo utilizzare le regole di sicurezza per applicare l'accesso ai database di archiviazione in storage.rules. Tieni presente che possiamo utilizzare le funzioni anche per controlli più complessi:

rules_version  =  '2';

function  isImageBelowMaxSize(maxSizeMB)  {
	return  request.resource.size  <  maxSizeMB  *  1024  *  1024
		&&  request.resource.contentType.matches('image/.*');
}

 service  firebase.storage  {
	match  /b/{bucket}/o  {
		match  /{userId}/{postId}/{filename}  {
			allow  write:  if  request.auth  !=  null
			&&  request.auth.uid  ==  userId  &&  isImageBelowMaxSize(5);
			allow  read;
		}
	}
}