Cum să creați o aplicație Vue Survey utilizând autentificarea și baza de date Firebase

Publicat: 2022-03-10
Rezumat rapid ↬ Acest tutorial vă va conduce pe un ghid pas cu pas pentru a crea o aplicație funcțională de sondaj folosind Vue.js și Firebase. De la validarea datelor utilizatorului prin Vuelidate, până la autentificare, stocarea datelor utilizatorului, protecția rutei și trimiterea datelor către serverele Firebase. Toți pașii utilizați în tutorial sunt practici și pot fi reproduși în orice proiect din viața reală, chiar și cu un backend personalizat.

În acest tutorial, veți construi o aplicație Survey, în care vom învăța să validăm datele din formularul utilizatorilor noștri, să implementăm autentificarea în Vue și să putem primi date de sondaj folosind Vue și Firebase (o platformă BaaS).

Pe măsură ce construim această aplicație, vom învăța cum să gestionăm validarea formularelor pentru diferite tipuri de date, inclusiv să luăm legătura cu backend-ul pentru a verifica dacă un e-mail a fost deja primit, chiar înainte ca utilizatorul să trimită formularul în timpul înscrierii.

De asemenea, aplicația s-ar ocupa de autentificarea utilizatorului cu API-uri odihnitoare. Acesta va folosi Authguard în routerul Vue pentru a împiedica utilizatorii care nu sunt autentificați să obțină acces la formularul de sondaj și să trimită cu succes datele sondajului utilizatorilor conectați la o bază de date securizată.

Doar ca să fim pe aceeași pagină, să clarificăm ce este Firebase și ce va face în acest tutorial. Firebase este un set de instrumente pentru „crearea, îmbunătățirea și creșterea aplicației”, vă oferă acces la o mare parte a serviciilor pe care dezvoltatorii ar trebui să le construiască ei înșiși, dar nu doresc cu adevărat să le construiască, deoarece ar prefera să le construiască. concentrați-vă pe experiența aplicației în sine. Aceasta include lucruri precum analiza, autentificarea, bazele de date, stocarea fișierelor, iar lista continuă.

Acest lucru este diferit de dezvoltarea tradițională a aplicațiilor, care implică de obicei scrierea atât a software-ului frontend, cât și a celui backend. Codul de interfață doar invocă punctele finale API expuse de backend, iar codul de backend realizează treaba. Cu toate acestea, cu produsele Firebase, backend-ul tradițional este ocolit, punând munca în client. Acest lucru permite, din punct de vedere tehnic, inginerilor front-end ca mine să construiască aplicații full-stack scriind doar cod front-end.

Mai multe după săritură! Continuați să citiți mai jos ↓

Concluzia este că Firebase va acționa ca backend-ul nostru în acest proiect, oferindu-ne punctele finale API necesare pentru a gestiona atât nevoile noastre de autentificare, cât și de baze de date. În cele din urmă, veți crea o aplicație de sondaj funcțională folosind Vue+ Firebase. După aceea, puteți continua și construi orice aplicație web la alegere folosind aceleași procese, chiar și cu un backend personalizat.

Pentru a urma, trebuie să aveți instalate Node și npm/yarn pe mașina dvs. Dacă nu ați făcut deja acest lucru, urmați aceste ghiduri rapide pentru a instala fire sau npm pe mașina dvs. De asemenea, trebuie să aveți o înțelegere de bază a sintaxei routerului Vue, Vuex și Vue pentru acest tutorial.

Fișierele de pornire pentru acest tutorial sunt chiar aici, care conține fișierele de bază pentru acest proiect, iar aici este repo-ul pentru demonstrația finalizată. Puteți clona sau descărca repozițiile și rulați npm install în terminalul dvs.

După instalarea fișierului de pornire, veți vedea o pagină de bun venit, care are opțiuni pentru a vă înscrie și a vă conecta. După ce v-ați conectat, puteți avea acces la sondaj.

Arhitectura aplicației Survey
Acesta descrie modul în care va funcționa aplicația noastră de sondaj. (Previzualizare mare)

Simțiți-vă liber să creați un nou proiect dacă doriți să construiți acest proiect în întregime pe cont propriu, asigurați-vă că instalați Vuex, Vue router, Vuelidate și axios în proiectul dumneavoastră Vue. Deci haideți să intrăm direct în:

În primul rând, vom avea nevoie de un cont Firebase pentru a configura acest proiect, care este foarte asemănător cu crearea unui container pentru aplicația noastră, oferindu-ne acces la baza de date, diverse mijloace de autentificare, găzduire etc. Este ușor de configurat odată ce sunteți pe site-ul Firebase.

Pagina de destinație Firebase
Pagina de destinație în care vă puteți înscrie și vă puteți începe călătoria Firebase. (Previzualizare mare)
Creați noi proiecte Firebase
Crearea proiectelor Firebase (previzualizare mare)

Acum că avem proiectul nostru, următorul lucru este să configuram atât sistemul nostru de autentificare, cât și baza de date (bază de date în timp real) pe Firebase.

  • Faceți clic pe opțiunea „autentificare”;
  • Configurați „metoda de conectare” pe care o dorim (în acest caz e-mail/parolă).
Configurați metoda de conectare
Configurați metoda de autentificare e-mail/parolă pentru proiect. (Previzualizare mare)
  • Faceți clic pe „bază de date”.
  • Alegeți „Baza de date în timp real” și copiați acest link care se află chiar deasupra.

Va fi foarte util ca punct final API atunci când dorim să trimitem datele către baza noastră de date Firebase.

Ne vom referi la acest API ca API-ul bazei de date. Pentru a-l utiliza, va trebui să adăugați numele bazei de date la alegere atunci când o trimiteți. De exemplu, pentru a trimite la o bază de date numită utilizator. Pur și simplu adăugați user.json la sfârșit:

 {databaseAPI}/user.json
Baza de date în timp real
Utilizați API-ul de deasupra bazei de date pentru a trimite date către baza de date. (Previzualizare mare)

După aceasta, vom accesa documentația API-ului de autentificare Firebase pentru a ne înscrie și a ne conecta punctele finale API. În aceste puncte finale, va fi nevoie de cheia API a proiectului nostru, care poate fi găsită în setările proiectului.

Validare

Revenind la codul nostru, va exista o validare a datelor de înscriere înainte de a fi trimise la server, doar pentru a vă asigura că utilizatorul trimite informații adecvate. Vom folosi Vuelidate, care este o bibliotecă grozavă care face validarea mai ușoară în Vue. Mai întâi de toate, instalați Vuelidate în proiect:

 npm i vuelidate

Accesați src/components/auth/signup.vue și, în eticheta de script, importați vuelidate și toate evenimentele necesare de care vom avea nevoie din bibliotecă, așa cum se vede mai jos.

Notă : Puteți verifica documentele pentru o prezentare completă a bibliotecii și a tuturor evenimentelor disponibile.

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

O explicație rapidă:

Descriere
Valoare
required Valoarea este obligatorie
email Valoarea trebuie să fie un e-mail
numeric Trebuie sa fie un numar
minValue Cea mai mică valoare numerică pe care utilizatorul o poate introduce.
sameAs Folosit pentru a compara două valori pentru a vă asigura că sunt aceleași
De asemenea, importați [`axios`](https://github.com/axios/axios) pentru a putea trimite o solicitare HTTP către server:
 import axios from 'axios'
Înainte de a continua, va trebui să adăugăm câteva reguli la baza de date pentru a putea valida e-mailul așa cum ar trebui, așa cum se vede mai jos:
Regulile Firebase
Regulile bazei de date vă ajută să decideți că puteți sau nu accesați baza de date în orice moment. (Previzualizare mare)
 "read" = "true"
Înseamnă că baza de date poate fi citită fără nicio piedică din partea clientului.
 "write" = "auth" !== null
Nu poți scrie în baza de date decât că ești un utilizator autentificat.
 "Users" = { "onIndex" : ["email"] }
Acest lucru ne permite să interogăm documentul „utilizatori” cu un index de „e-mail”. Adică, puteți filtra literalmente baza de date pentru un e-mail unic. Apoi adăugați o proprietate personalizată calculată cu numele `validations`, așa cum avem metode, calculate, etc. Sub `validations` vom avea metode de validare a datelor necesare începând de la `email` unde este necesar și, evident, trebuie să fie un e-mail . De asemenea, dorim să putem spune unui utilizator când un e-mail a fost deja preluat de altcineva, verificând baza de date după ce utilizatorul a tastat-o ​​folosind ceva numit validatoare asincrone, toate într-un validator personalizat și totul este susținut de [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 }) } } }
Apoi, sub unic, interogați baza de date folosind axios și utilizați Object.keys implicit pentru a returna răspunsul numai dacă lungimea acestuia este 0. Pentru vârstă, veți adăuga valoarea necesară, numerică și o valoare minimă de 18 care este atribuită lui `minVal. ` ca proprietățile sale.
 age: { required, numeric, minVal: minValue(18) }
Proprietățile parolei sunt necesare, cu o lungime minimă de 6 atribuită lui `minLen`.
 password: { required, minLen: minLength(6) }
Proprietățile `confirmPassword` trebuie să fie practic aceleași cu parola.
 confirmPassword: { sameAs: sameAs(vm => { return vm.password }) }
Pentru a spune utilizatorului că e-mailul este preluat, utilizați `v-if` pentru a verifica dacă `unique` este adevărat sau fals. Dacă este adevărat, înseamnă că lungimea obiectului returnat este 0, iar e-mailul poate fi folosit în continuare, precum și invers. În același mod, puteți verifica dacă introducerea utilizatorului este un e-mail real folosind `v-if`. Și pentru toate div-urile din jur pe intrarea individuală, vom adăuga o clasă de invalid care devine activă odată ce apare o eroare la intrarea respectivă. Pentru a lega evenimentele de validare la fiecare dintre intrările din HTML, folosim [`$touch()`](https://vuelidate.js.org/#sub-without-v-model) așa cum se vede cu `email ` mai jos.
 <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>
`Vârsta`, `parola` și `confirmPassword` vor fi legate de intrarea lor HTML într-un mod similar cu `e-mailul`. Și vom face butonul „Trimitere” inactiv dacă există o eroare în oricare dintre intrări.
 <button type="submit" :disabled="$v.$invalid">create</button>
Iată un [exemplu CodePen] complet (https://codepen.io/atanda1/pen/Yzyqrjv) pentru această secțiune vuelidate.
Implementarea Vuelidate
Vuelidate este folosit aici pentru a determina tipul de date trimise la baza de date. (Previzualizare mare)
## Autentificare Această aplicație este un SPA și nu se reîncarcă ca site-urile tradiționale, așa că vom folosi Vuex, ca „sursă de adevăr” unică, pentru a permite fiecărei componente din aplicația noastră să fie conștientă de starea generală de autentificare. Mergem la fișierul magazinului nostru și creăm atât metoda de conectare/înregistrare în cadrul acțiunilor. Răspunsul (`token` și `userId`) primit când trimitem datele utilizatorilor, vor fi stocate în starea noastră. Acest lucru este important deoarece simbolul va fi folosit pentru a ști dacă suntem încă conectați sau nu în orice moment în aplicația noastră. `Token`, `userId` și utilizatorul sunt create în starea cu o valoare inițială nulă. Vom ajunge la utilizator mult mai târziu, dar deocamdată ne vom concentra pe primele două.
 state: { idToken: null, userId: null, user: null }
Mutațiile sunt apoi create pentru a schimba starea atunci când este necesar.
authUser Salvează token-ul și userId
storeUser Stochează informațiile despre utilizator
clearAuthData Șterge datele înapoi la starea inițială
 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 } }
Pentru înregistrare/conectare, va trebui să creăm acțiuni individuale pentru ambele, unde trimitem cererile noastre de autentificare către server. După care răspunsul nostru (token și userId) de la înregistrare/conectare este trimis la authUser și salvat în stocarea 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)) }
Dar iată partea dificilă, ceea ce vom face cu acțiunea de înregistrare în special este să trimitem doar e-mailul și parola pentru a fi înregistrate în baza de date de autentificare. În sens real, nu avem acces pentru a folosi datele din această bază de date de autentificare și nu am trimis niciuna dintre datele noastre de înregistrare în afară de e-mail/parolă. Deci, ceea ce vom face este să creăm o altă acțiune pentru a trimite datele complete de înregistrare către o altă bază de date. În acest document separat al bazei de date, vom avea acces complet la toate informațiile pe care alegem să le salvăm acolo. Vom numi această nouă acțiune se numește `storeUser`. Apoi mergem la acțiunea noastră de înregistrare și trimitem întregul obiect care conține datele noastre de înregistrare la o bază de date la care avem acces acum prin `storeUser`. **Notă:** Este posibil să nu doriți să trimiteți parola utilizatorului cu `storeUser` la baza de date din motive de securitate.
 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` adaugă o interogare folosind token-ul și API-ul de bază de date recent obținute în timpul postării în baza de date. Acest lucru se datorează faptului că nu putem scrie în baza noastră de date, cu excepția faptului că suntem autentificați cu dovada noastră (jetonul). Aceasta este regula pe care am dat-o la Firebase la început, vă amintiți?
 “write” = “auth” !== null
Codul complet pentru acțiunile de înscriere/conectare este chiar [aici](https://codepen.io/atanda1/pen/mdePKqj). Apoi trimiteți atât înregistrarea, cât și conectarea din componentele lor în cadrul metodei `onSubmit` la acțiunile respective din magazin.
 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) } } }
**Notă:** `signupData` conține datele formularului.
 methods : { onSubmit = { const formData = { email : this.email, password : this.password } this.$store.dispatch('login', {email: formData.email, password: formData.password}) } }
## AuthGuard Este nevoie ca AuthGuard să împiedice utilizatorii care nu sunt autentificați să aibă acces la tabloul de bord unde vor trimite sondajul. Accesați fișierul de rută și importați magazinul nostru.
 import store from './store'
În cadrul traseului, accesați calea tabloului de bord și adăugați următoarele:
 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') } } } ]
Tot ce face acest lucru este să verificăm dacă există un token în stare, dacă da, dăm acces la tabloul de bord și invers. ## Deconectare Pentru a crea opțiunea noastră de deconectare, vom folosi `clearAuth` pe care l-am creat mai devreme sub `mutations`, care doar setează atât `token`, cât și `userId` la `null`. Acum creăm o nouă „acțiune de deconectare”, care se angajează la „clearAuth”, șterge spațiul de stocare local și adăugăm „router.replace('/')” pentru a redirecționa complet utilizatorul.
 actions: { logout ({commit}) { commit('clearAuth') localStorage.removeItem('token') localStorage.removeItem('userId') router.replace('/') } }
În componenta antet, avem o metodă `onLogout` care trimite acțiunea noastră de deconectare în magazin.
 methods: { onLogout() { this.$store.dispatch('logout') } }
Apoi adăugăm un `@click` la butonul care declanșează metoda `onLogout` așa cum putem vedea [aici](https://codepen.io/atanda1/pen/jObqKNd).
 <ul @click="onLogout">Log Out</ul>
## UI_State Acum că am acordat acces condiționat la tabloul de bord, următorul pas este să îl eliminați din bara de navigare, astfel încât numai utilizatorii autentificați să îl poată vizualiza. Pentru a face asta, am adăuga o nouă metodă sub `getters` numită `ifAuthenticated` care verifică dacă token-ul din starea noastră este nul. Când există un simbol, acesta arată că utilizatorul este autentificat și dorim ca acesta să vadă opțiunea tabloului de bord al sondajului în bara de navigare.
 getters: { isAuthenticated (state) { return state.idToken !== null } }
După care, vă întoarceți la componenta antet și creați o metodă `auth` sub computed, care trimite către `isAuthenticated` din `getters` pe care tocmai le-am creat în magazin. Ceea ce face acest lucru este că `isAuthenticated` va returna false dacă nu există un simbol, ceea ce înseamnă că `auth` ar fi, de asemenea, nul și invers.
 computed: { auth () { return this.$store.getters.ifAuthenticated } }
După aceasta, adăugăm un `v-if` la HTML-ul nostru pentru a verifica dacă `auth` este nul sau nu, determinând dacă acea opțiune va apărea pe bara de navigare.
 <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>
- Veți găsi codul complet al secțiunii UI State [aici](https://codepen.io/atanda1/pen/QWjNxyo).
Statul UI
Există o schimbare în antet în funcție de starea de autentificare a utilizatorului. (Previzualizare mare)

Logare automata

Când ne reîncărcăm aplicația, pierdem datele și suntem deconectați, fiind nevoiți să o luăm de la capăt. Acest lucru se datorează faptului că jetonul și ID-ul nostru sunt stocate în Vuex, care este javascript, și asta înseamnă că aplicația noastră este reîncărcată cu browserul când este reîmprospătată.

Și, în sfârșit, ceea ce vom face este să recuperăm jetonul din stocarea noastră locală. Procedând astfel, putem avea jetonul utilizatorului în browser, indiferent de momentul în care reîmprospătăm fereastra și putem avea o metodă de autentificare automată a utilizatorului, în măsura în care jetonul este încă valabil.

Este creată o nouă metodă de actions numită AutoLogin , în care vom obține token-ul și userId -ul din stocarea locală și vom trimite datele noastre la metoda authUser în mutații.

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

Apoi mergem la App.vue și scriem o metodă created , care va trimite autoLogin din magazinul nostru de fiecare dată când aplicația este încărcată.

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

Preluare_date_utilizator

Dorim să salutăm utilizatorul pe tabloul de bord afișând numele utilizatorului. Și astfel, este creată o altă acțiune numită fetchUser care verifică mai întâi dacă există un token ca de obicei. Apoi, primește e-mailul din stocarea locală și interogează baza de date așa cum sa făcut mai devreme cu validarea e-mailului.

Aceasta returnează un obiect care conține datele utilizatorului trimise inițial în timpul înscrierii. Apoi convertim acest obiect într-o matrice și îl trimitem la mutația storeUser creată inițial.

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

După care creăm un alt getter numit user care returnează state.user deja comis prin storeUser .

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

Înapoi la tabloul de bord, creăm o nouă metodă calculată numită name care returnează state.user.name numai dacă utilizatorul există.

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

Și vom adăuga, de asemenea, proprietatea calculată created pentru a trimite acțiunea fetchUser odată ce pagina este încărcată. Apoi folosim v-if în HTML-ul nostru pentru a afișa numele dacă numele există.

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

Send_Survey

Pentru a trimite sondajul, vom crea o acțiune postData care trimite datele la baza de date folosind API-ul bazei de date, cu simbolul pentru a arăta serverului că utilizatorul este conectat.

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

Ne întoarcem la componenta tabloului de bord și trimitem datele la acțiunea noastră postData din magazin.

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

Iată-l, avem o mulțime de funcții utile implementate în aplicația noastră demonstrativă în timp ce comunicăm cu serverul nostru Firebase. Sperăm că veți folosi aceste funcții puternice în următorul proiect, deoarece sunt foarte esențiale pentru construirea de aplicații web moderne astăzi.

Dacă aveți întrebări, le puteți lăsa în secțiunea de comentarii și voi răspunde cu plăcere la fiecare dintre ele!

  • Demo-ul pentru tutorial este live aici.
Aplicația pentru sondaj Vue
Aplicația de sondaj finalizată (previzualizare mare)

Alte resurse care se pot dovedi utile includ:

  • Pentru a înțelege mai multe despre Firebase și despre celelalte servicii pe care le oferă, consultați articolul lui Chris Esplin, „Ce este Firebase?”
  • Vuelidate este o bibliotecă foarte frumoasă în care ar trebui să te uiți cu adevărat. Ar trebui să citiți documentația acesteia pentru a obține o perspectivă completă.https://vuelidate.js.org/.
  • De asemenea, puteți explora axios singur, mai ales dacă doriți să îl utilizați în proiecte mai mari.