Atelier de programmation sur les frameworks Web Angular Firebase

1. Ce que vous allez créer

Dans cet atelier de programmation, vous allez créer un blog de voyage avec une carte collaborative en temps réel à l'aide de la dernière version de notre bibliothèque Angular : AngularFire. L'application Web finale sera un blog de voyage où vous pourrez importer des images pour chaque lieu que vous avez visité.

AngularFire sera utilisé pour créer l'application Web, la suite d'émulateurs pour les tests locaux, Authentication pour suivre les données utilisateur, Firestore et Storage pour conserver les données et les contenus multimédias, le tout optimisé par Cloud Functions, et enfin Firebase Hosting pour déployer l'application.

Points abordés

  • Développer en local avec les produits Firebase et la suite d'émulateurs
  • Améliorer votre application Web avec AngularFire
  • Faire persister vos données dans Firestore
  • Conserver des éléments multimédias dans Storage
  • Déployer votre application sur Firebase Hosting
  • Utiliser Cloud Functions pour interagir avec vos bases de données et vos API

Prérequis

  • Node.js version 10 ou ultérieure
  • Un compte Google pour créer et gérer votre projet Firebase
  • La CLI Firebase version 11.14.2 ou ultérieure
  • Un navigateur de votre choix, tel que Chrome
  • Connaissances de base sur Angular et JavaScript

2. Obtenir l'exemple de code

Clonez le dépôt GitHub de l'atelier de programmation à partir de la ligne de commande :

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

Si vous n'avez pas installé git, vous pouvez également télécharger le dépôt sous forme de fichier ZIP.

Le dépôt GitHub contient des exemples de projets adaptés à différentes plates-formes.

Cet atelier de programmation n'utilise que le dépôt webframework :

  • 📁 webframework : code de départ sur lequel vous allez vous appuyer dans cet atelier de programmation.

Installer des dépendances

Après le clonage, installez les dépendances dans le dossier racine et functions avant de créer l'application Web.

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

Installer la CLI Firebase

Installez la CLI Firebase en exécutant cette commande dans un terminal :

npm install -g firebase-tools

Vérifiez que votre version de la CLI Firebase est supérieure à 11.14.2 en exécutant la commande suivante :

firebase  --version

Si votre version est antérieure à 11.14.2, veuillez la mettre à jour en utilisant la commande suivante :

npm update firebase-tools

3. Créer et configurer un projet Firebase

Créer un projet Firebase

  1. Connectez-vous à la console Firebase à l'aide de votre compte Google.
  2. Cliquez sur le bouton pour créer un projet, puis saisissez un nom de projet (par exemple, FriendlyChat).
  3. Cliquez sur Continuer.
  4. Si vous y êtes invité, lisez et acceptez les Conditions d'utilisation de Firebase, puis cliquez sur Continuer.
  5. (Facultatif) Activez l'assistance IA dans la console Firebase (appelée "Gemini dans Firebase").
  6. Pour cet atelier de programmation, vous n'avez pas besoin de Google Analytics. Désactivez donc l'option Google Analytics.
  7. Cliquez sur Créer un projet, attendez que votre projet soit provisionné, puis cliquez sur Continuer.

Ajouter une application Web Firebase au projet

  1. Cliquez sur l'icône Web pour créer une application Web Firebase.
  2. À l'étape suivante, un objet de configuration s'affiche. Copiez le contenu de cet objet dans le fichier environments/environment.ts.

Configurer les produits Firebase

L'application que nous allons créer utilise des produits Firebase disponibles pour les applications Web :

  • Firebase Authentication, pour permettre à vos utilisateurs de se connecter facilement à votre application.
  • Cloud Firestore, pour sauvegarder des données structurées sur le cloud et être notifié instantanément en cas de modification des données.
  • Cloud Storage for Firebase, pour sauvegarder des fichiers dans le cloud.
  • Firebase Hosting, pour héberger et diffuser vos éléments.
  • Fonctions permettant d'interagir avec des API internes et externes.

Certains de ces produits nécessitent une configuration particulière ou doivent être activés via la console Firebase.

Activer la connexion Google pour Firebase Authentication

Pour permettre aux utilisateurs de se connecter à l'application Web avec leur compte Google, nous allons utiliser la méthode de connexion Google.

Pour activer la connexion Google :

  1. Dans la console Firebase, localisez la section Créer dans le panneau de gauche.
  2. Cliquez sur Authentification, puis sur l'onglet Méthode de connexion (ou cliquez ici pour y accéder directement).
  3. Activez le fournisseur de connexion Google, puis cliquez sur Enregistrer.
  4. Définissez le nom public de votre application sur <your-project-name> et choisissez une adresse e-mail d'assistance pour le projet dans le menu déroulant.

Activer Cloud Firestore

  1. Dans la section Build de la console Firebase, cliquez sur Firestore Database (Base de données Firestore).
  2. Cliquez sur Créer une base de données dans le volet Cloud Firestore.
  3. Définissez l'emplacement de stockage de vos données Cloud Firestore. Vous pouvez conserver cette valeur par défaut ou choisir une région proche de vous.

Activer Cloud Storage

L'application Web utilise Cloud Storage for Firebase pour stocker, importer et partager des photos.

  1. Dans la section Créer de la console Firebase, cliquez sur Storage.
  2. Si le bouton Commencer n'est pas disponible, cela signifie que le stockage cloud est déjà

est activée, vous n'avez pas besoin de suivre les étapes ci-dessous.

  1. Cliquez sur Commencer.
  2. Lisez la clause de non-responsabilité concernant les règles de sécurité pour votre projet Firebase, puis cliquez sur Suivant.
  3. L'emplacement Cloud Storage est présélectionné avec la même région que celle que vous avez choisie pour votre base de données Cloud Firestore. Cliquez sur OK pour terminer la configuration.

Conformément aux règles de sécurité par défaut, tout utilisateur authentifié peut enregistrer ce qu'il souhaite dans Cloud Storage. Nous améliorerons la sécurité du stockage plus tard dans cet atelier de programmation.

4. Se connecter à votre projet Firebase

L'interface de ligne de commande (CLI) Firebase vous permet d'utiliser Firebase Hosting pour diffuser votre application Web en local, ainsi que pour la déployer dans votre projet Firebase.

Assurez-vous que votre ligne de commande accède au répertoire webframework local de votre application.

Associez le code de l'application Web à votre projet Firebase. Tout d'abord, connectez-vous à la CLI Firebase en ligne de commande :

firebase login

Exécutez ensuite la commande suivante pour créer un alias de projet. Remplacez $YOUR_PROJECT_ID par l'ID de votre projet Firebase.

firebase  use  $YOUR_PROJECT_ID

Ajouter AngularFire

Pour ajouter AngularFire à l'application, exécutez la commande suivante :

ng add @angular/fire

Suivez ensuite les instructions de la ligne de commande et sélectionnez les fonctionnalités qui existent dans votre projet Firebase.

Initialiser Firebase

Pour initialiser le projet Firebase, exécutez la commande suivante :

firebase init

Ensuite, en suivant les invites de ligne de commande, sélectionnez les fonctionnalités et les émulateurs utilisés dans votre projet Firebase.

Démarrer les émulateurs

Depuis le répertoire webframework, exécutez la commande suivante pour démarrer les émulateurs :

firebase  emulators:start

Le résultat devrait se présenter comme suit :

$  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.

Lorsque le message ✔All emulators ready! s'affiche, les émulateurs sont prêts à être utilisés.

Vous devriez voir l'UI de votre application de voyage, qui ne fonctionne pas (pas encore !) :

N'attendez plus pour en profiter !

5. Connecter l'application Web aux émulateurs

D'après le tableau des journaux de l'émulateur, l'émulateur Cloud Firestore écoute sur le port 8080 et l'émulateur Authentication écoute sur le port 9099.

Ouvrir EmulatorUI

Dans votre navigateur Web, accédez à http://127.0.0.1:4000/. L'interface utilisateur de la suite d'émulateurs devrait s'afficher.

Router l'application pour qu'elle utilise les émulateurs

Dans src/app/app.module.ts, ajoutez le code suivant à la liste des importations de 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'application est désormais configurée pour utiliser des émulateurs locaux, ce qui permet d'effectuer des tests et des développements en local.

6. Ajouter l'authentification

Maintenant que les émulateurs sont configurés pour l'application, nous pouvons ajouter des fonctionnalités d'authentification pour nous assurer que chaque utilisateur est connecté avant de publier des messages.

Pour ce faire, nous pouvons importer les fonctions signin directement depuis AngularFire et suivre l'état d'authentification de votre utilisateur avec la fonction authState. Modifiez les fonctions de la page de connexion pour que la page vérifie l'état d'authentification de l'utilisateur au chargement.

Injecter AngularFire Auth

Dans src/app/pages/login-page/login-page.component.ts, importez Auth à partir de @angular/fire/auth et injectez-le dans LoginPageComponent. Les fournisseurs d'authentification, tels que Google, et les fonctions telles quesignin et signout peuvent également être importés directement à partir du même package et utilisés dans l'application.

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 page de connexion est désormais fonctionnelle. Essayez de vous connecter et consultez les résultats dans l'émulateur d'authentification.

7. Configurer Firestore

Au cours de cette étape, vous allez ajouter des fonctionnalités pour publier et mettre à jour des articles de blog de voyage stockés dans Firestore.

Comme pour Authentication, les fonctions Firestore sont préemballées à partir d'AngularFire. Chaque document appartient à une collection et peut également contenir des collections imbriquées. Pour créer et mettre à jour un article de blog de voyage, vous devez connaître le path du document dans Firestore.

Implémenter TravelService

Étant donné que de nombreuses pages différentes devront lire et mettre à jour les documents Firestore dans l'application Web, nous pouvons implémenter les fonctions dans src/app/services/travel.service.ts pour éviter d'injecter à plusieurs reprises les mêmes fonctions AngularFire sur chaque page.

Commencez par injecter Auth, comme à l'étape précédente, ainsi que Firestore dans notre service. Il est également utile de définir un objet observable user$ qui écoute l'état d'authentification actuel.

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);

Ajouter un post de voyage

Les posts de voyage existeront sous forme de documents stockés dans Firestore. Étant donné que les documents doivent exister dans des collections, la collection contenant tous les posts de voyage sera nommée travels. Le chemin d'accès de tout post de voyage sera donc travels/.

À l'aide de la fonction addDoc d'AngularFire, un objet peut être inséré dans une collection :

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;

	})
}

Modifier et supprimer des données

Étant donné l'UID d'un post de voyage, il est possible de déduire le chemin d'accès du document stocké dans Firestore, qui peut ensuite être lu, mis à jour ou supprimé à l'aide des fonctions updateFoc et deleteDoc d'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)
}

Lire les données en tant qu'observable

Étant donné que les posts de voyage et les étapes en cours de route peuvent être modifiés après leur création, il serait plus utile d'obtenir des objets de document en tant qu'observables, pour s'abonner à toutes les modifications apportées. Cette fonctionnalité est proposée par les fonctions docData et collectionData de @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[]>
}

Ajouter des arrêts à un post de voyage

Maintenant que les opérations de post de voyage sont configurées, il est temps de considérer les arrêts, qui existeront sous une sous-collection d'un post de voyage comme suit : travels//stops/

Cette procédure est presque identique à la création d'un post de voyage. Essayez de l'implémenter vous-même ou consultez l'implémentation ci-dessous :

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

Pratique ! Les fonctions Firestore ont été implémentées dans le service de voyage. Vous pouvez maintenant les voir à l'œuvre.

Utiliser les fonctions Firestore dans l'application

Accédez à src/app/pages/my-travels/my-travels.component.ts et injectez TravelService pour utiliser ses fonctions.

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

TravelService est appelé dans le constructeur pour obtenir un tableau Observable de tous les voyages.

Si vous n'avez besoin que des trajets de l'utilisateur actuel, utilisez la fonction query.

D'autres méthodes permettent d'assurer la sécurité, comme l'implémentation de règles de sécurité ou l'utilisation de Cloud Functions avec Firestore, comme indiqué dans les étapes facultatives ci-dessous.

Il vous suffit ensuite d'appeler les fonctions implémentées dans TravelService.

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

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

La page "Mes voyages" devrait maintenant fonctionner. Découvrez ce qui se passe dans votre émulateur Firestore lorsque vous créez un post de voyage.

Répétez ensuite l'opération pour les fonctions de mise à jour dans /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. Configurer le stockage

Vous allez maintenant implémenter Storage pour stocker des images et d'autres types de contenus multimédias.

Cloud Firestore est idéal pour stocker des données structurées, telles que des objets JSON. Cloud Storage est conçu pour stocker des fichiers ou des blobs. Dans cette application, vous l'utiliserez pour permettre aux utilisateurs de partager leurs photos de voyage.

Comme pour Firestore, le stockage et la mise à jour de fichiers avec Storage nécessitent un identifiant unique pour chaque fichier.

Implémentons les fonctions dans TraveService :

Importer un fichier

Accédez à src/app/services/travel.service.ts et injectez Storage depuis AngularFire :

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

Implémentez la fonction d'importation :

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 principale différence entre l'accès aux documents depuis Firestore et aux fichiers depuis Cloud Storage est que, bien qu'ils suivent tous deux des chemins structurés en dossiers, la combinaison de l'URL de base et du chemin d'accès est obtenue via getDownloadURL, qui peut ensuite être stocké et utilisé dans un fichier .

Utiliser la fonctionnalité dans l'application

Accédez à src/app/components/edit-stop/edit-stop.component.ts et appelez la fonction d'importation à l'aide de :

	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);
}

Lorsque l'image est importée, le fichier multimédia lui-même est importé dans le stockage, et l'URL est stockée en conséquence dans le document Firestore.

9. Déployer l'application

Nous sommes maintenant prêts à déployer l'application.

Copiez les configurations firebase de src/environments/environment.ts vers src/environments/environment.prod.ts, puis exécutez la commande suivante :

firebase deploy

L'écran qui s'affiche devrait ressembler à ce qui suit :

 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. Félicitations !

Votre application devrait maintenant être complète et déployée sur Firebase Hosting. Toutes les données et analyses seront désormais accessibles dans la console Firebase.

Pour en savoir plus sur AngularFire, Functions et les règles de sécurité, n'oubliez pas de consulter les étapes facultatives ci-dessous, ainsi que les autres ateliers de programmation Firebase.

11. Facultatif : Gardes d'authentification AngularFire

En plus de Firebase Authentication, AngularFire propose également des protections basées sur l'authentification sur les routes, afin que les utilisateurs disposant d'un accès insuffisant puissent être redirigés. Cela permet de protéger l'application contre les accès des utilisateurs aux données protégées.

Dans src/app/app-routing.module.ts, importez

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

Vous pouvez ensuite définir des fonctions pour déterminer quand et où les utilisateurs doivent être redirigés sur certaines pages :

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

Il vous suffit ensuite de les ajouter à vos itinéraires :

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. Facultatif : règles de sécurité

Firestore et Cloud Storage utilisent des règles de sécurité (firestore.rules et security.rules, respectivement) pour appliquer la sécurité et valider les données.

Pour le moment, les données Firestore et Storage sont accessibles en lecture et en écriture, mais vous ne voulez pas que les utilisateurs puissent modifier les posts des autres. Vous pouvez utiliser des règles de sécurité pour restreindre l'accès à vos collections et documents.

Règles Firestore

Pour autoriser uniquement les utilisateurs authentifiés à afficher les posts de voyage, accédez au fichier firestore.rules et ajoutez :

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;
	}
}

Les règles de sécurité peuvent également être utilisées pour valider les données :

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;
	}
}

Règles de stockage

De même, nous pouvons utiliser des règles de sécurité pour appliquer l'accès aux bases de données de stockage dans storage.rules. Notez que nous pouvons également utiliser des fonctions pour des vérifications plus complexes :

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;
		}
	}
}