Comment créer une application Vue Survey à l'aide de l'authentification et de la base de données Firebase

Publié: 2022-03-10
Résumé rapide ↬ Ce didacticiel vous guidera étape par étape pour créer une application d'enquête fonctionnelle à l'aide de Vue.js et Firebase. De la validation des données de l'utilisateur via Vuelidate à l'authentification, en passant par le stockage des données de l'utilisateur, la protection des itinéraires et l'envoi de données aux serveurs Firebase. Toutes les étapes utilisées dans le didacticiel sont pratiques et peuvent être reproduites dans n'importe quel projet réel, même avec un backend personnalisé.

Dans ce didacticiel, vous allez créer une application d'enquête, où nous apprendrons à valider les données de formulaire de nos utilisateurs, à implémenter l'authentification dans Vue et à pouvoir recevoir des données d'enquête à l'aide de Vue et Firebase (une plate-forme BaaS).

Au fur et à mesure que nous construisons cette application, nous apprendrons à gérer la validation de formulaire pour différents types de données, y compris en contactant le backend pour vérifier si un e-mail est déjà pris, avant même que l'utilisateur ne soumette le formulaire lors de l'inscription.

En outre, l'application gérerait la connexion de l'utilisateur avec des API reposantes. Il utilisera Authguard dans le routeur Vue pour empêcher les utilisateurs non connectés d'accéder au formulaire d'enquête et envoyer avec succès les données d'enquête des utilisateurs connectés à une base de données sécurisée.

Juste pour que nous soyons sur la même page, clarifions ce qu'est Firebase et ce qu'il fera dans ce didacticiel. Firebase est un ensemble d'outils pour "créer, améliorer et développer votre application", il vous donne accès à une grande partie des services que les développeurs devraient normalement créer eux-mêmes, mais ne veulent pas vraiment créer, car ils préfèrent concentrez-vous sur l'expérience de l'application elle-même. Cela inclut des éléments tels que l'analyse, l'authentification, les bases de données, le stockage de fichiers, etc.

Ceci est différent du développement d'applications traditionnel, qui implique généralement l'écriture de logiciels frontend et backend. Le code frontal appelle simplement les points de terminaison de l'API exposés par le backend, et le code backend fait le travail. Cependant, avec les produits Firebase, le backend traditionnel est contourné, laissant le travail au client. Cela permet techniquement aux ingénieurs frontaux comme moi de créer des applications complètes en écrivant uniquement du code frontal.

Plus après saut! Continuez à lire ci-dessous ↓

L'essentiel est que Firebase agirait comme notre backend dans ce projet en nous fournissant les points de terminaison API nécessaires pour gérer à la fois nos besoins d'authentification et de base de données. Au final, vous aurez créé une application d'enquête fonctionnelle à l'aide de Vue+ Firebase. Après cela, vous pouvez continuer et créer n'importe quelle application Web de votre choix en utilisant ces mêmes processus, même avec un backend personnalisé.

Pour suivre, vous devez avoir installé Node et npm/yarn sur votre machine. Si vous ne l'avez pas déjà fait, suivez ces guides rapides pour installer le fil ou le npm sur votre machine. Vous devez également avoir une compréhension de base de la syntaxe des routeurs Vue, Vuex et Vue pour ce didacticiel.

Les fichiers de démarrage de ce didacticiel se trouvent ici, qui contiennent les fichiers de base de ce projet, et voici le référentiel de la démo terminée. Vous pouvez cloner ou télécharger les dépôts et exécuter npm install dans votre terminal.

Après avoir installé le fichier de démarrage, vous verrez une page d'accueil, qui propose des options pour vous inscrire et vous connecter. Une fois connecté, vous pourrez alors accéder à l'enquête.

Architecture de l'application d'enquête
Ceci décrit comment notre application d'enquête va fonctionner. ( Grand aperçu )

N'hésitez pas à créer un nouveau projet si vous souhaitez créer ce projet entièrement par vous-même, assurez-vous simplement d'installer Vuex, Vue router, Vuelidate et axios dans votre projet Vue. Alors allons-y directement :

Tout d'abord, nous aurons besoin d'un compte Firebase pour configurer ce projet, ce qui revient à créer un conteneur pour notre application, nous donnant accès à la base de données, à divers moyens d'authentification, à l'hébergement, etc. C'est simple à configurer une fois que vous êtes sur le site Firebase.

Page de destination Firebase
La page de destination où vous pouvez vous inscrire et commencer votre voyage Firebase. ( Grand aperçu )
Créer de nouveaux projets Firebase
Création de projets Firebase ( Grand aperçu )

Maintenant que nous avons notre projet, la prochaine étape consiste à configurer à la fois notre système d'authentification et notre base de données (base de données en temps réel) sur Firebase.

  • Cliquez sur l'option "authentification" ;
  • Configurez la "méthode de connexion" que nous voulons (dans ce cas, e-mail/mot de passe).
Configurer la méthode de connexion
Configurez la méthode d'authentification par e-mail/mot de passe pour le projet. ( Grand aperçu )
  • Cliquez sur "base de données".
  • Choisissez "Base de données en temps réel" et copiez ce lien qui se trouve juste en haut.

Ce sera très utile en tant que point de terminaison de l'API lorsque nous voulons envoyer les données à notre base de données firebase.

Nous appellerons cette API l'API de la base de données. Pour l'utiliser, vous devrez ajouter le nom de la base de données de votre choix lors de son envoi. Par exemple, pour envoyer à une base de données appelée user. Vous ajoutez simplement user.json à la fin :

 {databaseAPI}/user.json
Base de données en temps réel
Utilisez l'API au-dessus de la base de données elle-même pour envoyer des données à la base de données. ( Grand aperçu )

Après cela, nous irons ensuite à la documentation de l'API Firebase auth rest pour obtenir notre inscription et nous connecter aux points de terminaison de l'API. Dans ces points de terminaison, il y aura un besoin pour la clé API de notre projet, qui se trouve dans nos paramètres de projet.

Validation

De retour à notre code, il y aura une validation des données d'inscription avant d'être envoyées au serveur, juste pour s'assurer que l'utilisateur envoie les informations appropriées. Nous utiliserons Vuelidate qui est une bibliothèque sympa qui facilite la validation dans Vue. Tout d'abord, installez Vuelidate dans le projet :

 npm i vuelidate

Accédez à src/components/auth/signup.vue et dans la balise de script, importez vuelidate et tous les événements nécessaires dont nous aurons besoin de la bibliothèque, comme indiqué ci-dessous.

Remarque : Vous pouvez consulter la documentation pour un aperçu complet de la bibliothèque et de tous les événements disponibles.

 import { required, email, numeric, minValue, minLength, sameAs } from 'vuelidate/lib/validators'

Une explication rapide :

La description
Évaluer
required La valeur est obligatoire
email La valeur doit être un e-mail
numeric Doit être un nombre
minValue Plus petite valeur numérique que l'utilisateur peut entrer.
sameAs Utilisé pour comparer deux valeurs afin de s'assurer qu'elles sont identiques
Importez également [`axios`](https://github.com/axios/axios) pour pouvoir envoyer une requête HTTP au serveur :
 import axios from 'axios'
Avant de continuer, nous devrons ajouter quelques règles à la base de données pour pouvoir valider l'e-mail comme il se doit, comme indiqué ci-dessous :
Règles Firebase
Les règles de la base de données vous aident à décider si vous pouvez ou non accéder à la base de données à tout moment. ( Grand aperçu )
 "read" = "true"
Cela signifie que la base de données peut être lue sans aucune entrave du côté client.
 "write" = "auth" !== null
Vous ne pouvez pas écrire sur la base de données sauf si vous êtes un utilisateur authentifié.
 "Users" = { "onIndex" : ["email"] }
Cela nous permet d'interroger le document `users` avec un index de `email`. Autrement dit, vous pouvez littéralement filtrer la base de données pour un e-mail unique. Ajoutez ensuite une propriété calculée personnalisée avec le nom `validations` tout comme nous avons des méthodes, des calculs, etc. Sous `validations` nous aurons des méthodes pour valider les données nécessaires à partir de `email` où elles sont requises et doivent évidemment être un e-mail . De plus, nous voulons être en mesure d'informer un utilisateur lorsqu'un e-mail a déjà été pris par quelqu'un d'autre, en vérifiant la base de données après que l'utilisateur l'a tapé à l'aide de quelque chose appelé validateurs asynchrones, le tout dans un validateur personnalisé et tout est pris en charge par [vuelidate. ](https://vuelidate.js.org/#sub-asynchronous-validation)
 validations : { email: { required, email, unique: val => { if (val === '') return true return axios.get('https://vue-journal.firebaseio.com/users.json?orderBy="email"&equalTo="' + val + '"') .then(res => { return Object.keys(res.data).length === 0 }) } } }
Ensuite, sous unique, interrogez la base de données à l'aide d'axios et utilisez les Object.keys par défaut pour renvoyer la réponse uniquement si sa longueur est de 0. Pour l'âge, vous ajouterez obligatoire, numérique et une valeur minimale de 18 attribuée à `minVal ` comme ses propriétés.
 age: { required, numeric, minVal: minValue(18) }
Les propriétés du mot de passe sont obligatoires, avec une longueur minimale de 6 attribuées à `minLen`.
 password: { required, minLen: minLength(6) }
Les propriétés `confirmPassword` doivent être identiques au mot de passe.
 confirmPassword: { sameAs: sameAs(vm => { return vm.password }) }
Pour dire à l'utilisateur que l'e-mail est pris, utilisez `v-if` pour vérifier si `unique` est vrai ou faux. Si vrai, cela signifie que la longueur de l'objet renvoyé est de 0 et que le courrier électronique peut toujours être utilisé et vice versa. De la même manière, vous pouvez vérifier si l'entrée de l'utilisateur est un e-mail réel en utilisant `v-if`. Et pour toutes les divs environnantes sur l'entrée individuelle, nous ajouterons une classe invalide qui devient active une fois qu'il y a une erreur sur cette entrée. Pour lier les événements de validation à chacune des entrées dans le HTML, nous utilisons [`$touch()`](https://vuelidate.js.org/#sub-without-v-model) comme on le voit avec le `email ` ci-dessous.
 <div class="input" :class="{invalid: $v.email.$error}"> <h6 v-if="!$v.email.email">Please provide a valid email address.</h6> <h6 v-if="!$v.email.unique">This email address has been taken.</h6> <input type="email" placeholder="Email" @blur="$v.email.$touch()" v-model="email"> </div>
`Age`, `password` et `confirmPassword` seront liés à leur entrée HTML de la même manière que `email`. Et nous rendrons le bouton "Soumettre" inactif s'il y a une erreur dans l'une des entrées.
 <button type="submit" :disabled="$v.$invalid">create</button>
Voici un [exemple CodePen] complet (https://codepen.io/atanda1/pen/Yzyqrjv) pour cette section vuelidate.
Implémentation de Vuelidate
Vuelidate est utilisé ici pour déterminer le type de données envoyées à la base de données. ( Grand aperçu )
## Authentification Cette application est un SPA et ne se recharge pas comme les sites traditionnels. Nous utiliserons donc Vuex comme notre unique "source de vérité" pour permettre à chaque composant de notre application de connaître l'état général de l'authentification. Nous allons dans notre fichier de magasin et créons les deux méthodes de connexion/inscription dans les actions. La réponse (`token` et `userId`) reçue lorsque nous envoyons les données des utilisateurs, va être stockée dans notre état. Ceci est important car le jeton sera utilisé pour savoir si nous sommes toujours connectés ou non à tout moment dans notre application. Le `token`, `userId` et l'utilisateur sont créés dans l'état avec une valeur initiale de null. Nous aborderons l'utilisateur beaucoup plus tard, mais pour l'instant, nous nous concentrerons sur les deux premiers.
 state: { idToken: null, userId: null, user: null }
Des mutations sont ensuite créées pour changer l'état en cas de besoin.
authUser Enregistre le jeton et l' userId
storeUser Stocke les informations de l'utilisateur
clearAuthData Efface les données à l'état initial
 mutations: { authUser (state, userData) { state.idToken = userData.token state.userId = userData.userId }, storeUser (state, user) { state.user = user }, clearAuthData (state) { state.idToken = null state.userId = null state.user = null } }
Pour l'inscription/la connexion, nous devrons créer des actions individuelles pour les deux, où nous enverrons nos demandes d'authentification au serveur. Après quoi, notre réponse (token et userId) de l'inscription/de la connexion est validée pour authUser et enregistrée sur le stockage local.
 signup ({commit, dispatch}, authData) { axios.post('https://www.googleapis.com/identitytoolkit/v3/relyingparty/signupNewUser?key=AIzaSyCFr-OMMzDGp4Mmr0t66w2cTGfNazYjptQ', { email: authData.email, password: authData.password, returnSecureToken: true }) .then(res => { console.log(res) commit('authUser', { token: res.data.idToken, userId: res.data.localId }) localStorage.setItem('token', res.data.idToken) localStorage.setItem('userId', res.data.localId) localStorage.setItem('email', res.data.email) dispatch('storeUser', authData) setTimeout(function () { router.push('/dashboard') }, 3000) }) .catch(error => console.log(error)) }
 login ({commit}, authData) { axios.post('https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=AIzaSyCFr-OMMzDGp4Mmr0t66w2cTGfNazYjptQ', { email: authData.email, password: authData.password, returnSecureToken: true }) .then(res => { console.log(res) localStorage.setItem('token', res.data.idToken) localStorage.setItem('userId', res.data.localId) localStorage.setItem('email', res.data.email) commit('authUser', { token: res.data.idToken, userId: res.data.localId }) router.push('/dashboard') }) .catch(error => console.log(error.message)) }
Mais voici la partie délicate, ce que nous ferons avec l'action d'inscription en particulier est d'envoyer uniquement l'e-mail et le mot de passe à enregistrer dans la base de données d'authentification. Dans la réalité, nous n'avons pas accès aux données de cette base de données d'authentification et nous n'avons envoyé aucune de nos données d'inscription à part l'e-mail/le mot de passe. Nous allons donc créer une autre action pour envoyer les données d'inscription complètes à une autre base de données. Dans ce document de base de données séparé, nous aurons un accès complet à toutes les informations que nous choisissons d'y enregistrer. Nous appellerons cette nouvelle action `storeUser`. Nous allons ensuite à notre action d'inscription et envoyons l'objet entier contenant nos données d'inscription à une base de données à laquelle nous avons maintenant accès via `storeUser`. **Remarque :** Vous ne souhaitez peut-être pas envoyer le mot de passe de votre utilisateur avec `storeUser` à la base de données pour des raisons de sécurité.
 storeUser ({ state}, userData) { if (!state.idToken) { return } axios.post('https://vue-journal.firebaseio.com/users.json' + '?auth=' + state.idToken, userData) .then(res => console.log(res)) .catch(error => console.log(error)) } }
`storeUser` ajoute une requête à l'aide de notre API de jeton et de base de données nouvellement obtenue lors de la publication dans la base de données. C'est parce que nous ne pouvons pas écrire dans notre base de données, sauf que nous sommes authentifiés avec notre preuve (le jeton). C'est la règle que nous avons donnée à Firebase au début, vous vous souvenez ?
 “write” = “auth” !== null
Le code complet pour les actions d'inscription/de connexion se trouve juste [ici](https://codepen.io/atanda1/pen/mdePKqj). Envoyez ensuite l'inscription et la connexion à partir de leurs composants dans la méthode "onSubmit" aux actions respectives dans le magasin.
 methods : { onSubmit () { const signupData = { email : this.email, name : this.name, age : this.age, password : this.password, confirmPassword : this.co nfirmPassword } this.$store.dispatch('signup', signupData) } } }
**Remarque :** `signupData` contient les données du formulaire.
 methods : { onSubmit = { const formData = { email : this.email, password : this.password } this.$store.dispatch('login', {email: formData.email, password: formData.password}) } }
## AuthGuard Il est nécessaire qu'AuthGuard empêche les utilisateurs non connectés d'accéder au tableau de bord où ils enverront l'enquête. Accédez au fichier de route et importez notre magasin.
 import store from './store'
Dans la route, accédez au chemin du tableau de bord et ajoutez ce qui suit :
 const routes = [ { path: '/', component: WelcomePage }, { path: '/signup', component: SignupPage }, { path: '/signin', component: SigninPage }, { path: '/dashboard', component: DashboardPage, beforeEnter (to, from, next) { if (store.state.idToken) { next() } else { next('/signin') } } } ]
Tout cela ne fait que vérifier s'il y a un jeton dans l'état, si oui, nous donnons accès au tableau de bord et vice versa. ## LogOut Pour créer notre option de déconnexion, nous utiliserons `clearAuth` que nous avons créé précédemment sous `mutations` qui définit simplement le `token` et `userId` sur `null`. Nous créons maintenant une nouvelle `action` `logout`, qui s'engage sur `clearAuth`, supprime le stockage local et ajoute `router.replace('/')` pour rediriger complètement l'utilisateur.
 actions: { logout ({commit}) { commit('clearAuth') localStorage.removeItem('token') localStorage.removeItem('userId') router.replace('/') } }
Dans le composant d'en-tête, nous avons une méthode "onLogout" qui distribue notre action de déconnexion dans le magasin.
 methods: { onLogout() { this.$store.dispatch('logout') } }
Nous ajoutons ensuite un `@click` au bouton qui déclenche la méthode `onLogout` comme nous pouvons le voir [ici](https://codepen.io/atanda1/pen/jObqKNd).
 <ul @click="onLogout">Log Out</ul>
## UI_State Maintenant que nous avons accordé un accès conditionnel au tableau de bord, l'étape suivante consiste à le supprimer de la barre de navigation, afin que seuls les utilisateurs authentifiés puissent le voir. Pour ce faire, nous ajouterions une nouvelle méthode sous les `getters` appelée `ifAuthenticated` qui vérifie si le jeton dans notre état est nul. Lorsqu'il y a un jeton, cela montre que l'utilisateur est authentifié et nous voulons qu'il voie l'option de tableau de bord d'enquête sur la barre de navigation.
 getters: { isAuthenticated (state) { return state.idToken !== null } }
Après quoi, vous revenez au composant d'en-tête et créez une méthode `auth` sous computed, qui envoie à notre `isAuthenticated` dans les `getters` que nous venons de créer dans le magasin. Cela signifie que `isAuthenticated` renverrait false s'il n'y avait pas de jeton, ce qui signifie que `auth` serait également nul et vice versa.
 computed: { auth () { return this.$store.getters.ifAuthenticated } }
Après cela, nous ajoutons un `v-if` à notre HTML pour vérifier si `auth` est nul ou non, déterminant si cette option s'affichera sur la barre de navigation.
 <li v-if='auth'> <router-link to="/dashboard">Dashboard</router-link> </li> <li v-if='!auth'> <router-link to="/signup">Register</router-link> </li> <li v-if='!auth'> <router-link to="/signin">Log In</router-link> </li>
- Vous trouverez le code complet de la section UI State [ici](https://codepen.io/atanda1/pen/QWjNxyo).
État de l'interface utilisateur
L'en-tête change en fonction du statut d'authentification de l'utilisateur. ( Grand aperçu )

Connexion automatique

Lorsque nous rechargeons notre application, nous perdons les données et sommes déconnectés, devant tout recommencer. En effet, notre jeton et notre identifiant sont stockés dans Vuex, qui est en javascript, ce qui signifie que notre application est rechargée avec le navigateur lors de l'actualisation.

Et donc finalement, ce que nous allons faire est de récupérer le jeton dans notre stockage local. Ce faisant, nous pouvons avoir le jeton de l'utilisateur sur le navigateur, quel que soit le moment où nous actualisons la fenêtre, et disposer d'une méthode de connexion automatique de notre utilisateur tant que le jeton est toujours valide.

Une nouvelle méthode d' actions appelée AutoLogin est créée, où nous obtiendrons le jeton et l' userId utilisateur du stockage local, et engagerons nos données dans la méthode authUser dans les mutations.

 actions : { AutoLogin ({commit}) { const token = localStorage.getItem('token') if (!token) { return } const userId = localStorage.getItem('userId') const token = localStorage.getItem('token') commit('authUser', { idToken: token, userId: userId }) } }

Nous allons ensuite dans notre App.vue et écrivons une méthode created , qui enverra l' autoLogin de notre magasin à chaque chargement de l'application.

 created () { this.$store.dispatch('AutoLogin') }

Récupérer_données_utilisateur

Nous voulons souhaiter la bienvenue à l'utilisateur sur le tableau de bord en affichant le nom de l'utilisateur. Et ainsi, une autre action appelée fetchUser est créée qui vérifie d'abord s'il y a un jeton comme d'habitude. Ensuite, il récupère l'e-mail à partir du stockage local et interroge la base de données comme précédemment avec la validation de l'e-mail.

Cela renvoie un objet contenant les données de l'utilisateur initialement soumises lors de l'inscription. Nous convertissons ensuite cet objet en tableau et le commitons dans la mutation storeUser initialement créée.

 fetchUser ({ commit, state}) { if (!state.idToken) { return } const email = localStorage.getItem('email') axios.get('https://vue-journal.firebaseio.com/users.json?orderBy="email"&equalTo="' + email + '"') .then(res => { console.log(res) // const users = [] console.log(res.data) const data = res.data const users = [] for (let key in data) { const user = data[key] user.id = key users.push(user) console.log(users) } commit('storeUser', users[0]) }) .catch(error => console.log(error)) }

Après quoi, nous créons un autre getter appelé user qui renvoie le state.user déjà validé via storeUser .

 getters: { user (state) { return state.user }, isAuthenticated (state) { return state.idToken !== null } }

De retour au tableau de bord, nous créons une nouvelle méthode calculée appelée name qui renvoie state.user.name uniquement si l'utilisateur existe.

 computed: { name () { return !this.$store.getters.user ? false : this.$store.getters.user.name } }, created () { this.$store.dispatch('fetchUser') } }

Et nous ajouterons également la propriété calculée created pour envoyer l'action fetchUser une fois la page chargée. Nous utilisons ensuite le v-if dans notre HTML afin d'afficher le nom si le nom existe.

 <p v-if="name">Welcome, {{ name }} </p>

Send_Survey

Pour envoyer l'enquête, nous allons créer une action postData qui envoie les données à la base de données à l'aide de l'API de base de données, avec le jeton pour montrer au serveur que l'utilisateur est connecté.

 postData ({state}, surveyData) { if (!state.idToken) { return } axios.post('https://vue-journal.firebaseio.com/survey.json' + '?auth=' + state.idToken , surveyData) .then(res => { console.log(res) }) .catch(error => console.log(error)) }

Nous revenons au composant de tableau de bord et envoyons les données à notre action postData dans le magasin.

 methods : { onSubmit () { const postData = { price: this.price, long: this.long, comment: this.comment } console.log(postData) this.$store.dispatch('postData', postData) } }

Voilà, nous avons beaucoup de fonctionnalités utiles implémentées dans notre application de démonstration tout en communiquant avec notre serveur Firebase. J'espère que vous utiliserez ces fonctionnalités puissantes dans votre prochain projet, car elles sont très essentielles à la création d'applications Web modernes aujourd'hui.

Si vous avez des questions, vous pouvez les laisser dans la section des commentaires et je serai heureux de répondre à chacune d'entre elles !

  • La démo du tutoriel est en direct ici.
Application d'enquête Vue
L'application d'enquête terminée ( Grand aperçu )

D'autres ressources qui peuvent s'avérer utiles comprennent :

  • Pour en savoir plus sur Firebase et les autres services qu'il propose, consultez l'article de Chris Esplin, "Qu'est-ce que Firebase ?"
  • Vuelidate est une très belle bibliothèque dans laquelle vous devriez vraiment creuser. Vous devriez lire sa documentation pour en avoir un aperçu complet.https://vuelidate.js.org/.
  • Vous pouvez également explorer axios seul, surtout si vous souhaitez l'utiliser dans des projets plus importants.