Cette série d'articles est indexée sur NgateSystems.com. Vous y trouverez également une fonction de recherche par mot-clé très utile.
Dernière révision : 24 novembre
Lorsque vous avez créé votre première base de données Firestore à l'aide de la publication 2.3, vous vous souvenez peut-être qu'on vous a demandé si vous souhaitiez appliquer des règles de « production » ou de « test ». Il était alors suggéré de sélectionner des règles « tests ». Si vous aviez utilisé l'onglet « règles » sur la page Firestore de la console Firebase à ce stade, vous auriez constaté que vos règles étaient définies sur quelque chose comme :
match /{document=**} { allow read, write: if request.time < timestamp.date(2024, 10, 31); }
Ici, Google a créé une règle par défaut qui utilise un horodatage pour autoriser l'accès en lecture et en écriture à votre base de données pendant 30 jours à compter du jour de sa création. Il est peu probable que ce soit ce que vous souhaitez maintenant (et Google vous demandera de le modifier de toute façon). Il est donc maintenant temps d'en savoir plus sur les règles Firestore et sur la manière dont vous pouvez les utiliser pour sécuriser votre base de données.
Les "règles" Firestore vous permettent de restreindre l'accès en lecture et en écriture aux collections de bases de données, en faisant référence à un objet de requête Firebase qui est transmis à un "gestionnaire de règles" Firestore chaque fois qu'un appel à la base de données est effectué. Cet objet contient, entre autres, les détails de l'utilisateur effectuant la demande, le type d'opération en cours et l'heure actuelle. Si vous souhaitez voir la liste complète des propriétés, chatGPT se fera un plaisir de vous la fournir.
Pour obtenir un compte rendu complet de la syntaxe des règles Firestore, il est probablement préférable que je vous renvoie aux propres documents de Google sur Premiers pas avec les règles Firestore. Pour les besoins actuels, je vais me concentrer sur les exigences immédiates de la base de données par défaut créée par cette série d'articles.
Pour voir une règle de base de données en action, essayez d'utiliser l'onglet « règles » sur la page Firestore de votre console Firebase pour modifier vos règles en :
match /{document=**} { allow read: if true; allow write: if request.time < timestamp.date(2000, 01, 01); }
Cette règle autorise uniquement l'accès en écriture aux documents de votre base de données si l'heure est antérieure au 1er janvier 2000. Ainsi, à moins que vous n'utilisiez actuellement une machine à remonter le temps, vous ne pourrez plus créer de nouveau documenter.
Cliquez sur le bouton "Publier" pour rendre la nouvelle règle active (vous pouvez ignorer en toute sécurité le message indiquant que la publication peut prendre un certain temps avant de prendre effet - en pratique, le délai semble minime), et voyez comment votre webapp réagit
Démarrez votre serveur de développement et lancez la webapp sur http://localhost:5173. Lorsque vous essayez d'ajouter un nouveau produit, vous ne devriez pas être trop surpris lorsque vous recevez une page « 500 : erreur interne ». Lorsque vous accédez à votre session de terminal pour rechercher la cause, vous verrez le message suivant :
match /{document=**} { allow read, write: if request.time < timestamp.date(2024, 10, 31); }
Maintenant que vous avez une idée du fonctionnement des règles Firestore, vous pouvez commencer à réfléchir à la façon dont vous pourriez les utiliser sur les pages d'affichage et de maintenance des produits que vous avez créées dans la publication 3.1.
Comme vous vous en souviendrez, ceux-ci proposaient deux itinéraires comme suit :
L'hypothèse est que même si vous serez heureux de permettre à n'importe qui de lire les documents sur les produits en utilisant la voie « affichage des produits », vous souhaiterez que seules les personnes autorisées soient pouvoir ajouter de nouveaux produits en utilisant la voie "produits-maintenance".
Les individus seront autorisés en leur fournissant une combinaison "identifiant utilisateur/mot de passe" qu'ils pourront utiliser pour se "connecter" à la webapp. Cette procédure créera un état « d'authentification » persistant sur l'appareil client de l'utilisateur qui deviendra une partie de l'objet de requête Firebase transmis au traitement des règles Firestore lorsque l'utilisateur tentera d'accéder à une base de données.
Ensuite, si vous définissez les règles Firestore comme suit :
match /{document=**} { allow read: if true; allow write: if request.time < timestamp.date(2000, 01, 01); }
seuls les utilisateurs "connectés" pourront écrire sur la page "produits".
Maintenant, tout ce que vous devez savoir, c'est comment rédiger une page de « connexion » pour créer un état d'authentification. Continuez à lire !
Dans un écran de connexion, les utilisateurs potentiels du système sont invités à fournir un identifiant personnel (généralement une adresse e-mail) et un mot de passe associé.
Le système vérifie ensuite l'identifiant et le mot de passe de l'utilisateur par rapport à une liste sécurisée d'informations d'identification connues. Dans Firebase, vous trouverez cette liste dans la console Firebase de votre projet sous l'onglet "Construire -> Authentification -> Utilisateurs". Jetez un œil à ceci. Profitez-en pour enregistrer une adresse e-mail et un mot de passe de test (l'enregistrement "programmatique" est également possible mais n'est pas abordé ici). Notez le "Champ UID utilisateur" que Firebase alloue à l'enregistrement. Il s'agit d'une version unique et cryptée de l'adresse e-mail. Comme vous le verrez bientôt, cela constitue un élément important du mécanisme de sécurité de Firebase. Notez également que l'écran offre des fonctionnalités pour supprimer des comptes et modifier des mots de passe.
Pendant que vous êtes ici, consultez l'onglet « Méthode de connexion » sur l'écran « Authentification ». Des combinaisons email/mot de passe ou des comptes Google sont proposés. Je vous recommande d'activer uniquement l'option email/mot de passe à ce stade.
Créez maintenant un écran de connexion. L'exemple de code présenté ci-dessous est étonnamment bref (et l'essentiel est du style !) :
[FirebaseError: Missing or insufficient permissions.] { code: 'permission-denied', customData: undefined, toString: [Function (anonymous)] }
Créez de nouveaux dossiers de route et des fichiers page.svelte pour les scripts de connexion et de déconnexion. Mais n'essayez pas de les exécuter pour l'instant, car je dois vous parler de quelques éléments supplémentaires !
Remarquez que ces fichiers importent désormais leur variable d'authentification à partir d'un fichier central src/lib/utilities/firebase-client.js. À l'intérieur, l'application Web présente ses clés Firebase-config pour garantir à Firebase qu'elle est autorisée à créer un objet d'authentification. Voici la version mise à jour de src/lib/utilities/firebase-client.js qui fait cela.
match /{document=**} { allow read, write: if request.time < timestamp.date(2024, 10, 31); }
Étant donné que les variables app, auth et db exportées ici sont largement requises dans une application Web, une grande partie du code est enregistrée en les générant dans un emplacement central.
Mais quelques morceaux de « bling » ici nécessitent quelques explications.
Tout d'abord, vous remarquerez que je ne code plus les propriétés firebaseConfig telles que apiKey directement dans le code mais je fais référence aux paramètres Vite que j'ai définis dans le fichier .env du projet (un fichier ou un dossier avec un "." signifie qu'il s'agit de données "système"). Le voici :
match /{document=**} { allow read: if true; allow write: if request.time < timestamp.date(2000, 01, 01); }
Tout l'intérêt du fichier .env est de mettre vos clés firebaseConfig dans un fichier qui ne contient pas de code d'application. Cela vous permet de gérer beaucoup plus facilement leur sécurité. Mais mettons cela de côté pour le moment afin que vous puissiez vous concentrer sur des choses plus importantes. J'ai ajouté une note à la fin de cet article qui, je l'espère, expliquera tout.
Une deuxième fonctionnalité qui peut vous dérouter est la const app = !getApps().length ? initializeApp(firebaseConfig) : getApp(); doubler. Ceci est un exemple d'instruction "ternaire" Javascript (demandez à chatGPT d'expliquer comment cela fonctionne, si vous ne l'avez jamais rencontré auparavant). Son effet est de :
De retour dans le courant dominant maintenant, l'effet de tout cela est que, lorsqu'une connexion réussit, Firebase crée un objet "auth" pour l'utilisateur authentifié et l'enregistre en toute sécurité dans l'environnement du navigateur. Firebase peut ainsi, automatiquement, ajouter un jeton d'authentification généré à partir de celui-ci à chaque objet de requête transmis à une requête de service de base de données FireStore. Les informations contenues dans le jeton incluent des propriétés telles que l'identifiant « user uID » que vous avez vu précédemment dans l'onglet Authentification Firebase. Par conséquent, Firestore peut décider comment appliquer une règle telle que permettre l'écriture : if request.auth != null.
Tout cela signifie que l'activité Firestore côté client fonctionne comme sur des roulettes : une fois que vous êtes connecté, les règles Firestore prennent en charge tous les problèmes de sécurité de votre base de données.
Mais il y a un problème – un énorme problème, en fait. L'objet « auth » que Firebase a intégré dans l'environnement du navigateur n'est pas disponible pour les pages côté serveur comme inventor-maintenance/page.server.js.
Vous pouvez facilement le démontrer.
Publiez de nouvelles règles Firestore qui permettent à n'importe qui de lire tout ce qui concerne la collection de produits, mais garantissent que seules les personnes authentifiées peuvent rédiger des documents
match /{document=**} { allow read, write: if request.time < timestamp.date(2024, 10, 31); }
Connectez-vous en utilisant la route /login et recevez une alerte « vous êtes connecté avec Google ».
Lancez la page /products-display. Parce que les règles de Firestore permettent à n'importe qui de lire tout. La page affichera ainsi la liste actuelle des produits enregistrés, exactement comme auparavant.
Essayez d'ajouter un nouveau produit avec la page produits-maintenance. Ah ! Erreur !
match /{document=**} { allow read: if true; allow write: if request.time < timestamp.date(2000, 01, 01); }
Ce qui s'est passé ici, c'est que la variable d'authentification "écureuillée" du navigateur et le reste de ses informations de session Firebase parent ne sont pas disponibles pour Firestore sur le serveur. Par conséquent, request.auth n'y est pas défini et la règle Firestore échoue.
La position est que Google a refusé de fournir à Firebase une version côté serveur de l'excellente fonction de gestion de session qui rend la vie si agréable côté client. Actuellement, votre code utilise l'API Firestore Client. Sur le serveur, où une base de données Firestore a défini des « règles » sur une collection qui fait référence aux variables de session d'authentification Firebase, vous devez utiliser l'API Firestore Admin plutôt que l'API client. Les appels dans l'API Admin ne vérifient pas les règles Firestore, donc n'échouent pas lorsque l'authentification n'est pas définie. Mais l'utilisation de l'API Admin a plusieurs conséquences :
Gémir. Existe-t-il une alternative ? Les deux articles suivants montrent :
Cela a été une aventure difficile avec une fin malheureuse. Cependant, j'espère que vous aurez l'énergie de continuer à lire.
De votre point de vue de développeur, un code respectueux des règles sera un parfait délice car vous pourrez le déboguer entièrement à l'aide de l'outil Inspecteur du navigateur. Bien qu’il présente des limites, comme indiqué précédemment, il pourrait être parfaitement satisfaisant pour de nombreuses applications simples.
Alternativement, même si la version client-serveur présente de nouveaux défis, elle vous donnera une expérience précieuse dans les pratiques de développement traditionnelles et offrira des performances vraiment remarquables.
Aussi bizarre que cela puisse paraître, tout commence avec le logiciel de contrôle de version « Github » de Microsoft. Il s'agit d'une application Web gratuite qui vous permet de copier des copies sources dans un référentiel Web personnel. C'est devenu une norme de l'industrie et vous pouvez en apprendre davantage sur Une introduction douce à git et Github.
Son objectif principal est d'intégrer les activités d'équipes de développeurs travaillant en parallèle sur un même projet. Mais vous pourriez bien être intéressé à l'utiliser car, au cours du développement et de l'amélioration continue de vos projets personnels, il y aura des moments où vous souhaiterez placer un instantané « point de contrôle » de votre code dans un endroit sûr. .
Le problème est qu'il est trop facile pour des clés sensibles intégrées dans le code source d'être enregistrées par inadvertance dans un référentiel Git. Bien que les référentiels puissent être marqués comme « privés », la sécurité n'est pas garantie.
Une partie de la réponse consiste à organiser les choses de manière à ce que les clés du projet soient conservées séparément des fichiers de code. De cette façon, ils n'ont pas besoin d'être copiés dans Git. Placer vos clés Firebase dans votre fichier libutilitiesfirebase-client.js a été utile ici car cela signifiait que les clés n'étaient plus codées dans plusieurs fichiers page.server.js. Mais il y avait encore du code dans le firebase-client.js central que vous voudriez enregistrer dans votre dépôt. L'utilisation du fichier env vous permet enfin de démêler le code des clés. Bien que vos clés .env restent dans votre projet, ce fichier n'a plus besoin d'être copié dans le référentiel de code. Il peut donc être ajouté au fichier .gitignore qui indique à Git quels fichiers exclure.
Vous constaterez que Svelte a créé un fichier .gitignore lors de l'initialisation de votre projet et qu'il contient déjà des détails sur les dossiers système Vite qui n'ont pas leur place dans un point de contrôle du code source. Pour vous assurer qu'un fichier « .env » (et tout historique de modification du fichier) est exclu de tous les commits Git, vous devez ajouter les entrées suivantes :
match /{document=**} { allow read, write: if request.time < timestamp.date(2024, 10, 31); }
Notez qu'une fois que vous avez fait cela, la ligne /.env de votre répertoire VSCode Workspace deviendra "grisée". Cela fournit une assurance visuelle que ce fichier ne sera pas révélé sur le Web par un commit Git.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!