Blog

Firebase ed Angular: Realizzare un sistema di autenticazione

Tempo di lettura: 20 minuti

Alla fine di questa guida sarete in grado di realizzare e configurare un sistema di autenticazione con Firebase ed Angular. Mi aspetto che conosciate e sappiate utilizzare il framework per cui non scenderò nei particolari dello stesso ma lo darò per scontato.In caso contrario potete seguire il mio corso completo su Angular.

Firebase ed Angular: Configurare Firebase

Firebase è un database noSql dalle grandissime risorse, ad alta disponibilità ed integrabile in tempi rapidissimi in altri progetti software, semplicemente sottoscrivendo un account al servizio.

In breve è un potente servizio on line che permette di salvare e sincronizzare i dati elaborati da applicazioni web e mobile.

Collegatevi su firebase.google , se non avete un account google createlo, altrimenti cliccate in alto a destra su la mia console, come nell’immagine sotto:

Nello step successivo fate clic su aggiungi progetto:

nella scheda successiva date il nome al progetto, ad esempio , AFDemo e cliccate su continua:

quindi scegliete, o meno, se abilitare  Google Analytics (visto che si tratta di un tutorial io lo eviterei al momento) e cliccate su crea progetto ed infine su continua, si aprirà una scheda come la seguente:

quindi fate click su web come in figura, nello step successivo date un nome all’app e registratela, lasciate aperta questa scheda che ci servirà a breve.

Firebase: Imposta autenticazione con i social

Nel momento in cui andremo a realizzare un sistema di autenticazione con Angular e Firebase, ne gestiremo anche quello relativo ad una registrazione e login con i social quali possono essere Google, Facebook,Twitter,ecc…

Andate su Firebase , dirigetevi sulla mia console, aprite il progetto in essere:

ora a sinistra, nel menù, cliccate su Authentication, nella pagina che si apre cliccate su sign-in method:

abilitate le sezioni EMAIL/PASSWORD, GOOGLE,FACEBOOK , ciò consentirà di potersi registrare  e loggare tramite normale email o tutti quei social scelti(ovviamente scegliete i social a voi più congeniali).

Per quanto riguarda Facebook dovete prima collegarvi sulla console e realizzare una nuova App per ottenere l’APP ID e la  SECRET KEY ,potete seguire una guida da qui.

Bene abbiamo terminato, ora è arrivato il momento di installare Angular.

Installare Angular

Prima di installare Angular  sulla vostra macchina assicuratevi di avere installato l’ultima versione di Node.js.

Quindi aprite il terminale ed  installate il framework:

npm install -g @angular/cli

una volta terminata l’installazione impostate il progetto:

ng new angfire --inline-template --routing=true --skip-tests --minimal=true

prima di eseguire il comando sopra sceglietevi una directory nel pc a voi più congeniale, i progetti devono sempre essere ordinati. Questo creerà un progetto con un template inline , un file css non inline, il file  app-routing.module.ts  e non creerà il file .spec. Insomma avremo un progetto un po più leggero e veloce da gestire.

Ora , sempre da terminale, spostatevi all’interno della cartella creata.

cd angfire

Aggiungi il framework bootstrap alla tua applicazione

Al fine di avere un layout pulito e responsive aggiungeremo bootstrap alla nostra applicazione, quindi da terminale, sempre all’interno della root principale digitate:

npm install bootstrap

una volta terminata l’installazione aprite la root con il vostro ide preferito (io consiglio visual studio code , ide open source buono e potente), quindi aprite il file angular.json , cercate il nodo style ed aggiungete la seguente riga come di seguito:

"styles": [
            "node_modules/bootstrap/dist/css/bootstrap.min.css",
            "src/styles.css"
          ]

ora bootstrap è pronto all’uso.

Per testare il corretto funzionamento dell’app, da terminale ed all’interno dell root principale avviate il server:

ng serve -o

con il comando -o diciamo al server di aprire il browser predefinito automaticamente. Se ,http://localhost:4200/, si apre senza problemi tutto è andato come si deve.

Installare il package AngularFire2

Da terminale, sempre all’interno della root principale del progetto, digitate:

npm install firebase @angular/fire --save

Ora aprite i file environments.ts e environmets.prod.ts sotto la directory environmets e configurate firebase:

environments.ts
export const environment = {
  production: false,
  firebase: {
    apiKey: "AIzaSyBbosqYW8R1ms7hQet-yDBFOUX-OZJve04",
    authDomain: "afdemo-3ce3a.firebaseapp.com",
    databaseURL: "https://afdemo-3ce3a.firebaseio.com",
    projectId: "afdemo-3ce3a",
    storageBucket: "afdemo-3ce3a.appspot.com",
    messagingSenderId: "864779987928",
    appId: "1:864779987928:web:67146d0802edcbfe85a0ad"
  }
};
environments.prod.ts
export const environment = {
  production: true,
    firebase: {
      apiKey: "AIzaSyBbosqYW8R1ms7hQet-yDBFOUX-OZJve04",
      authDomain: "afdemo-3ce3a.firebaseapp.com",
      databaseURL: "https://afdemo-3ce3a.firebaseio.com",
      projectId: "afdemo-3ce3a",
      storageBucket: "afdemo-3ce3a.appspot.com",
      messagingSenderId: "864779987928",
      appId: "1:864779987928:web:67146d0802edcbfe85a0ad"
    }
};

In pratica i file environments ci consentono di differenziare le proprietà fra la produzione dell’applicazione e la modalità di sviluppo della stessa. Difatti in fase di sviluppo verrà caricato il primo (production: false) mentre in fase di build quindi produzione il secondo(production:true).

All’interno della proprietà firebase incollate le righe:

quindi aprite il file app.module ed importate i moduli relativi ad AngularFire ed il file environments.ts:

import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';

import {AppRoutingModule} from './app-routing.module';
import {AppComponent} from './app.component';
import {AngularFirestoreModule} from '@angular/fire/firestore';
import {AngularFireAuthModule} from '@angular/fire/auth';
import {AngularFireModule} from '@angular/fire';
import {environment} from '../environments/environment';

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        AngularFireModule.initializeApp(environment.firebase),
        AngularFireAuthModule,
        AngularFirestoreModule,
        BrowserModule,
        AppRoutingModule
    ],
    providers: [],
    bootstrap: [AppComponent]
})
export class AppModule {
}

Realizzare i componenti necessari

ng g c components/dashboard
ng g c components/sign-in
ng g c components/sign-up
ng g c components/forgot-password
ng g c components/verify-email

Crea le rotte

Apri il file app-routing.module.ts  ed aggiungi le seguenti righe al fine di creare i percorsi:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import {VerifyEmailComponent} from './components/verify-email/verify-email.component';
import {SignInComponent} from './components/sign-in/sign-in.component';
import {ForgotPasswordComponent} from './components/forgot-password/forgot-password.component';
import {SignUpComponent} from './components/sign-up/sign-up.component';
import {DashboardComponent} from './components/dashboard/dashboard.component';


const routes: Routes = [
  { path: '', redirectTo: '/sign-in', pathMatch: 'full' },
  { path: 'sign-in', component: SignInComponent },
  { path: 'register-user', component: SignUpComponent },
  { path: 'dashboard', component: DashboardComponent },
  { path: 'forgot-password', component: ForgotPasswordComponent },
  { path: 'verify-email-address', component: VerifyEmailComponent }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

Crea il service per l’autenticazione Firebase

Apri il terminale e digita:

ng generate interface shared/services/user

in questo modo ,innanzitutto, abbiamo creato una interfaccia da utilizzare come model per gli user, quindi apritelo e tipiziamo le nostre proprietà:

export interface User {
    uid: string;
    email: string;
    displayName: string;
    photoURL: string;
    emailVerified: boolean;
}

ora create il service:

ng g s shared/auth

quindi apritelo e digitate:

import { Injectable, NgZone } from '@angular/core';
import { User } from "./services/user";
import { auth } from 'firebase/app';
import { AngularFireAuth } from "@angular/fire/auth";
import { AngularFirestore, AngularFirestoreDocument } from '@angular/fire/firestore';
import { Router } from "@angular/router";

@Injectable({
    providedIn: 'root'
})

export class AuthService {
    userData: any; // Save logged in user data

    constructor(
        public afs: AngularFirestore,   // Inject Firestore service
        public afAuth: AngularFireAuth, // Inject Firebase auth service
        public router: Router,
        public ngZone: NgZone // NgZone service to remove outside scope warning
    ) {
        /* Saving user data in localstorage when
        logged in and setting up null when logged out */
        this.afAuth.authState.subscribe(user => {
            if (user) {
                this.userData = user;
                localStorage.setItem('user', JSON.stringify(this.userData));
                JSON.parse(localStorage.getItem('user'));
            } else {
                localStorage.setItem('user', null);
                JSON.parse(localStorage.getItem('user'));
            }
        })
    }

    // Sign in with email/password
    SignIn(email, password) {
        return this.afAuth.signInWithEmailAndPassword(email, password)
            .then((result) => {
                this.ngZone.run(() => {
                    this.router.navigate(['dashboard']);
                });
                this.SetUserData(result.user);
            }).catch((error) => {
                window.alert(error.message)
            })
    }

    // Sign up with email/password
    SignUp(email, password) {
        return this.afAuth.createUserWithEmailAndPassword(email, password)
            .then((result) => {
                /* Call the SendVerificaitonMail() function when new user sign
                up and returns promise */
                this.SendVerificationMail();
                this.SetUserData(result.user);
            }).catch((error) => {
                window.alert(error.message)
            })
    }

    // Send email verfificaiton when new user sign up
    SendVerificationMail() {
        return this.afAuth.currentUser.then((user) => {
            return user.sendEmailVerification();
        }).then(() => {
            this.router.navigate(['verify-email-address']);
        })
    }

    // Reset Forggot password
    ForgotPassword(passwordResetEmail) {
        return this.afAuth.sendPasswordResetEmail(passwordResetEmail)
            .then(() => {
                window.alert('Password reset email sent, check your inbox.');
            }).catch((error) => {
                window.alert(error)
            })
    }

    // Returns true when user is looged in and email is verified
    get isLoggedIn(): boolean {
        const user = JSON.parse(localStorage.getItem('user'));
        return (user !== null && user.emailVerified !== false) ? true : false;
    }

    // Sign in with Google
    GoogleAuth() {
        return this.AuthLogin(new auth.GoogleAuthProvider());
    }

    // Auth logic to run auth providers
    AuthLogin(provider) {
        return this.afAuth.signInWithPopup(provider)
            .then((result) => {
                this.ngZone.run(() => {
                    this.router.navigate(['dashboard']);
                })
                this.SetUserData(result.user);
            }).catch((error) => {
                window.alert(error)
            })
    }

    /* Setting up user data when sign in with username/password,
    sign up with username/password and sign in with social auth
    provider in Firestore database using AngularFirestore + AngularFirestoreDocument service */
    SetUserData(user) {
        const userRef: AngularFirestoreDocument<any> = this.afs.doc(`users/${user.uid}`);
        const userData: User = {
            uid: user.uid,
            email: user.email,
            displayName: user.displayName,
            photoURL: user.photoURL,
            emailVerified: user.emailVerified
        }
        return userRef.set(userData, {
            merge: true
        })
    }

    // Sign out
    SignOut() {
        return this.afAuth.signOut().then(() => {
            localStorage.removeItem('user');
            this.router.navigate(['sign-in']);
        })
    }

}

Questo file contiene la logica di base del nostro sistema di autenticazione. Viene gestito anche  l’accesso social utilizzando il provider di autenticazione Google di Firebase.

Il servizio di autenticazione gestisce l’accesso con nome utente / password, registrazione mediante e-mail / password, reimpostazione della password, verifica e-mail, protezione delle rotte utilizzando il metodo canActivate auth guard.

Firebase ed Angular: crea l’accesso con l’API firebase

Grazie al service Auth  gestiremo l’autenticazione dell’utente in Firebase ed Angular.

Quindi aprite il file sign-in / sign-in.component.ts  ed aggiungete le seguenti righe, dove ,innanzitutto, inietteremo il service nel costruttore in modo tale che le sue classi siano disponibili dappertutto:

import { Component, OnInit } from '@angular/core';
import {AuthService} from '../../shared/auth.service';

@Component({
  selector: 'app-sign-in',
  template: `
    <p>
      sign-in works!
    </p>
  `,
  styles: []
})
export class SignInComponent implements OnInit {

  constructor(public authService: AuthService) { }

  ngOnInit(): void {
  }

}

Ora modificate ancora aggiungendo nel template inline:

import { Component, OnInit } from '@angular/core';
import {AuthService} from '../../shared/auth.service';

@Component({
  selector: 'app-sign-in',
  template: `
    <div class="displayTable">
      <div class="displayTableCell">

        <div class="authBlock">
          <h3>Sign In</h3>
          <div class="formGroup">
            <input type="text" class="formControl" placeholder="Username" #userName required>
          </div>

          <div class="formGroup">
            <input type="password" class="formControl" placeholder="Password" #userPassword required>
          </div>

          <!-- Calling SignIn Api from AuthService -->
          <div class="formGroup">
            <input type="button" class="btn btnPrimary" value="Log in" (click)="authService.SignIn(userName.value, userPassword.value)">
          </div>

          <div class="formGroup">
            <span class="or"><span class="orInner">Or</span></span>
          </div>

          <!-- Calling GoogleAuth Api from AuthService -->
          <div class="formGroup">
            <button type="button" class="btn googleBtn" (click)="authService.GoogleAuth()">
              <i class="fab fa-google-plus-g"></i>
              Log in with Google
            </button>
          </div>

          <div class="forgotPassword">
            <span routerLink="/forgot-password">Forgot Password?</span>
          </div>
        </div>

        <div class="redirectToLogin">
          <span>Don't have an account?<span class="redirect" routerLink="/register-user"> Sign Up</span></span>
        </div>

      </div>
    </div>

  `,
  styles: []
})
export class SignInComponent implements OnInit {

  constructor(public authService: AuthService) { }

  ngOnInit(): void {
  }

}

aprite il file app.components e cancellate tutto ciò che c’è all’interno del template inline tranne <router-outlet> :

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <router-outlet></router-outlet>
  `,
  styles: []
})
export class AppComponent {
  title = 'angfire';
}

quindi avviate il server:

ng server --open

Registrazione dell’utente

E’ arrivato il momento di occuparci della registrazione di Firebase ed Angular, quindi aprite il file  sign-up / sign-up.component.ts ed iniettiamo ,come al solito, il service:

import { Component, OnInit } from '@angular/core';
import {AuthService} from '../../shared/auth.service';

@Component({
  selector: 'app-sign-up',
  template: `
    <p>
      sign-up works!
    </p>
  `,
  styles: []
})
export class SignUpComponent implements OnInit {

  constructor(public authService: AuthService) { }

  ngOnInit(): void {
  }

}

ricordatevi sempre , anche,  di importarlo.

Ora nel template , cancellate il tag <p>, ed inserite:

import { Component, OnInit } from '@angular/core';
import {AuthService} from '../../shared/auth.service';

@Component({
selector: 'app-sign-up',
template: `
<div class="displayTable">
<div class="displayTableCell">

<div class="authBlock">
<h3>Sign Up</h3>

<div class="formGroup">
<input type="email" class="formControl" placeholder="Email Address" #userEmail required>
</div>

<div class="formGroup">
<input type="password" class="formControl" placeholder="Password" #userPwd required>
</div>

<div class="formGroup">
<input type="button" class="btn btnPrimary" value="Sign Up" (click)="authService.SignUp(userEmail.value, userPwd.value)">
</div>

<div class="formGroup">
<span class="or"><span class="orInner">Or</span></span>
</div>

<!-- Continue with Google -->
<div class="formGroup">
<button type="button" class="btn googleBtn" (click)="authService.GoogleAuth()">
<i class="fab fa-google-plus-g"></i>
Continue with Google
</button>
</div>

<!-- Continue with Facebook -->
<!-- <div class="formGroup">-->
<!-- <button type="button" class="btn facebookBtn" (click)="authService.FacebookAuth()">-->
<!-- <i class="fab fa-facebook"></i>-->
<!-- Continue with Facebook-->
<!-- </button>-->
<!-- </div>-->
</div>

<div class="redirectToLogin">
<span>Already have an account? <span class="redirect" routerLink="/sign-in">Log In</span></span>
</div>
</div>

</div>
`,
styles: []
})
export class SignUpComponent implements OnInit {

constructor(public authService: AuthService) { }

ngOnInit(): void {
}

}

Firebase e Angular: password dimenticata

Bene ora andremo a realizzare le funzionalità per gestire i casi in cui non ci ricordassimo delle credenziali.

Apriamo il file forgot-password.component.ts ed iniettate il service Auth nel costruttore:

import { Component, OnInit } from '@angular/core';
import {AuthService} from '../../shared/auth.service';

@Component({
  selector: 'app-forgot-password',
  template: `
    <p>
      forgot-password works!
    </p>
  `,
  styles: []
})
export class ForgotPasswordComponent implements OnInit {

  constructor(public authService: AuthService) { }

  ngOnInit(): void {
  }

}

quindi modificate ed implementatene il template:

import { Component, OnInit } from '@angular/core';
import {AuthService} from '../../shared/auth.service';

@Component({
  selector: 'app-forgot-password',
  template: `
    <div class="displayTable">
      <div class="displayTableCell">
        <div class="authBlock">
          <h3>Reset Password</h3>

          <p class="text-center">Please enter your email address to request a password reset.</p>

          <div class="formGroup">
            <input type="email" class="formControl" placeholder="Email Address" #passwordResetEmail required>
          </div>

          <!-- Calling ForgotPassword from AuthService Api -->
          <div class="formGroup">
            <input type="submit" class="btn btnPrimary" value="Reset Password" (click)="authService.ForgotPassword(passwordResetEmail.value)">
          </div>
        </div>

        <div class="redirectToLogin">
          <span>Go back to ? <span class="redirect" routerLink="/sign-in">Log In</span></span>
        </div>

      </div>
    </div>
  `,
  styles: []
})
export class ForgotPasswordComponent implements OnInit {

  constructor(public authService: AuthService) { }

  ngOnInit(): void {
  }

}

Invio dell’email di verifica

In questa sezione implementeremo la classe responsabile della gestione dell’invio di una email di verifica nel caso in cui , appunto, ci fossimo scordati delle credenziali di accesso ed avessimo chiesto il reset della stessa.

Aprite il file verify-email / verify-email.component.ts ed iniettate il  service Auth nel costruttore:

import { Component, OnInit } from '@angular/core';
import {AuthService} from '../../shared/auth.service';

@Component({
  selector: 'app-verify-email',
  template: `
    <p>
      verify-email works!
    </p>
  `,
  styles: []
})
export class VerifyEmailComponent implements OnInit {

  constructor(public authService: AuthService) { }

  ngOnInit(): void {
  }

}

ora modificate il template:

import { Component, OnInit } from '@angular/core';
import {AuthService} from '../../shared/auth.service';

@Component({
  selector: 'app-verify-email',
  template: `
    <div class="displayTable">
      <div class="displayTableCell">

        <div class="authBlock">
          <h3>Thank You for Registering</h3>

          <div class="formGroup" *ngIf="authService.userData as user">
            <p class="text-center">We have sent a confirmation email to <strong>{{user.email}}</strong>.</p>
            <p class="text-center">Please check your email and click on the link to verfiy your email address.</p>
          </div>

          <!-- Calling SendVerificationMail() method using authService Api -->
          <div class="formGroup">
            <button type="button" class="btn btnPrimary" (click)="authService.SendVerificationMail()">
              <i class="fas fa-redo-alt"></i>
              Resend Verification Email
            </button>
          </div>

        </div>

        <div class="redirectToLogin">
          <span>Go back to?<span class="redirect" routerLink="/sign-in"> Sign in</span></span>
        </div>

      </div>
    </div>
  `,
  styles: []
})
export class VerifyEmailComponent implements OnInit {

  constructor(public authService: AuthService) { }

  ngOnInit(): void {
  }

}

Angular: Proteggere le rotte con i Route Guards

Angular integra di base una serie di funzionalità che sono estremamente utili se volete integrare un processo di autenticazione all’interno della vostra app.

Insieme all’interfaccia HttpInterceptor i servizi di Route Guards offrono la possibilità di realizzare un flow di autenticazione centralizzato e scalabile.

Angular e Firebase: Cos’è un Route Guard?

Un Route Guard è un’interfaccia che permette d’intercettare la navigazione su una determinata rotta e consentirne o meno l’accesso.

Prende questa decisione cercando un valore di ritorno,  o , da una classe che ne implementa la specifica interfaccia di protezione.

Esistono cinque diversi tipi di Guards che vengono attivati nell’ordine con cui sono elencati sotto e il comportamento del router viene modificato in modo diverso a seconda dell’interfaccia utilizzata.

Route Guards esistenti sono:

Se volete approfondire potete seguire il corso completo su Angular.

Apri il file  auth.service.ts e cerca il metodo isLoggedIn(). Questa funzione restituisce un risultato booleano  true quando l’utente è connesso. Se l’utente non viene trovato, restituirà false e non consentirà agli utenti di accedere alle pagine desiderate.

get isLoggedIn(): boolean {
    const user = JSON.parse(localStorage.getItem('user'));
    return (user !== null && user.emailVerified !== false) ? true : false;
}

Ecco abbiamo il dovere di proteggere le altre viste , le viste interne, per far ciò ci viene in aiuto la classe Route Guard, quindi generiamola da terminale:

ng generate guard shared/guard/auth

una volta generato ecco come si presenta il file auth.guard.ts:

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree } from '@angular/router';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {
  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
    return true;
  }
  
}

come potete notare è una classe simile al service, cioè è un injectable per poter essere utilizzata anche dappertutto nelle nostre classi.

Ora modifichiamo come di seguito:

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { Observable } from 'rxjs';
import {AuthService} from '../auth.service';

@Injectable({
  providedIn: 'root'
})

export class AuthGuard implements CanActivate {

  constructor(
      public authService: AuthService,
      public router: Router
  ){ }

  canActivate(
      next: ActivatedRouteSnapshot,
      state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    if(this.authService.isLoggedIn !== true) {
      this.router.navigate(['sign-in'])
    }
    return true;
  }

}

come si può vedere ho iniettato nel costruttore il service e la classe route che ci consente di navigare fra le viste, quindi ho protetto le rotte nel metodo canAcivate().

Ora dobbiamo avvisare la classe app-routing.module che ci sono pagine da proteggere, per cui aprite il file e aggiungete:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import {VerifyEmailComponent} from './components/verify-email/verify-email.component';
import {SignInComponent} from './components/sign-in/sign-in.component';
import {ForgotPasswordComponent} from './components/forgot-password/forgot-password.component';
import {SignUpComponent} from './components/sign-up/sign-up.component';
import {DashboardComponent} from './components/dashboard/dashboard.component';
import {AuthGuard} from './shared/guard/auth.guard';


const routes: Routes = [
  { path: '', redirectTo: '/sign-in', pathMatch: 'full' },
  { path: 'sign-in', component: SignInComponent },
  { path: 'register-user', component: SignUpComponent },
  { path: 'dashboard', component: DashboardComponent,canActivate: [AuthGuard] },
  { path: 'forgot-password', component: ForgotPasswordComponent },
  { path: 'verify-email-address', component: VerifyEmailComponent }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

è chiaro che bisognerà proteggere la pagina dashboard, rendendola accessibile solo previo login, allora ho aggiunto il metodo canActivate con AuthGuard nella rotta, ricordatevi di importare la classe {AuthGuard}, (il mio ide lo fa automaticamente, se il vostro non lo fa non ve ne scordate altrimenti genera errore).

Ora, salvate e provate a digitare http://localhost:4200/dashboard , se tutto funziona verrete reindirizzati alla pagina di login, abbiamo protetto la nostra dashboard.

Gestione dello stato di autenticazione Firebase con il LocalStorage

Questo passaggio spiega come gestire lo stato di autenticazione utente Firebase utilizzando l’API LocalStorage HTML. La gestione dei dati degli utenti registrati in Local Storage è molto semplice da gestire con Angular e Firebase.

Salveremo lo stato dell’utente nell’ Archiviazione locale, quando l’utente effettua l’accesso, i dettagli dello stesso saranno disponibili anche aggiornando la pagina.  Una volta che l’utente si disconnetterà, cioè effettuerà il logout, i dati saranno rimossi dallo storage.

Ecco come si presenta auth.service.ts :

import { Injectable, NgZone } from '@angular/core';
import { User } from "./services/user";
import { auth } from 'firebase/app';
import { AngularFireAuth } from "@angular/fire/auth";
import { AngularFirestore, AngularFirestoreDocument } from '@angular/fire/firestore';
import { Router } from "@angular/router";

@Injectable({
    providedIn: 'root'
})

export class AuthService {
    userData: any; // Save logged in user data

    constructor(
        public afs: AngularFirestore,   // Inject Firestore service
        public afAuth: AngularFireAuth, // Inject Firebase auth service
        public router: Router,
        public ngZone: NgZone // NgZone service to remove outside scope warning
    ) {
        /* Saving user data in localstorage when
        logged in and setting up null when logged out */
        this.afAuth.authState.subscribe(user => {
            if (user) {
                this.userData = user;
                localStorage.setItem('user', JSON.stringify(this.userData));
                JSON.parse(localStorage.getItem('user'));
            } else {
                localStorage.setItem('user', null);
                JSON.parse(localStorage.getItem('user'));
            }
        })
    }

    // Sign in with email/password
    SignIn(email, password) {
        return this.afAuth.signInWithEmailAndPassword(email, password)
            .then((result) => {
                this.ngZone.run(() => {
                    this.router.navigate(['dashboard']);
                });
                this.SetUserData(result.user);
            }).catch((error) => {
                window.alert(error.message)
            })
    }

    // Sign up with email/password
    SignUp(email, password) {
        return this.afAuth.createUserWithEmailAndPassword(email, password)
            .then((result) => {
                /* Call the SendVerificaitonMail() function when new user sign
                up and returns promise */
                this.SendVerificationMail();
                this.SetUserData(result.user);
            }).catch((error) => {
                window.alert(error.message)
            })
    }

    // Send email verfificaiton when new user sign up
    SendVerificationMail() {
        return this.afAuth.currentUser.then((user) => {
            return user.sendEmailVerification();
        }).then(() => {
            this.router.navigate(['verify-email-address']);
        })
    }

    // Reset Forggot password
    ForgotPassword(passwordResetEmail) {
        return this.afAuth.sendPasswordResetEmail(passwordResetEmail)
            .then(() => {
                window.alert('Password reset email sent, check your inbox.');
            }).catch((error) => {
                window.alert(error)
            })
    }

    // Returns true when user is looged in and email is verified
    get isLoggedIn(): boolean {
        const user = JSON.parse(localStorage.getItem('user'));
        return (user !== null && user.emailVerified !== false) ? true : false;
    }

    // Sign in with Google
    GoogleAuth() {
        return this.AuthLogin(new auth.GoogleAuthProvider());
    }
    // Sign in with Facebook
    FacebookAuth() {
        return this.AuthLogin(new auth.FacebookAuthProvider());
    }

    // Auth logic to run auth providers
    AuthLogin(provider) {
        return this.afAuth.signInWithPopup(provider)
            .then((result) => {
                this.ngZone.run(() => {
                    this.router.navigate(['dashboard']);
                })
                this.SetUserData(result.user);
            }).catch((error) => {
                window.alert(error)
            })
    }

    /* Setting up user data when sign in with username/password,
    sign up with username/password and sign in with social auth
    provider in Firestore database using AngularFirestore + AngularFirestoreDocument service */
    SetUserData(user) {
        const userRef: AngularFirestoreDocument<any> = this.afs.doc(`users/${user.uid}`);
        const userData: User = {
            uid: user.uid,
            email: user.email,
            displayName: user.displayName,
            photoURL: user.photoURL,
            emailVerified: user.emailVerified
        }
        return userRef.set(userData, {
            merge: true
        })
    }

    // Sign out
    SignOut() {
        return this.afAuth.signOut().then(() => {
            localStorage.removeItem('user');
            this.router.navigate(['sign-in']);
        })
    }

}

Abbiamo passato i dati dell’utente nel metodo localStorage.setItem() e abbiamo ottenuto i dati dal metodo localStorage.getItem('user').

Quindi aprite il componente dashboard.component.ts, iniettiamo il service in esso e modifichiamone il template come di seguito:

import { Component, OnInit } from '@angular/core';
import {AuthService} from '../../shared/auth.service';

@Component({
  selector: 'app-dashboard',
  template: `
    <!-- Top navigation -->
    <nav class="navbar navbar-dark fixed-top bg-dark flex-md-nowrap p-0 shadow">
      <a class="navbar-brand col-sm-3 col-md-2 mr-0">
        <img class="brand-logo" src="assets/logo-positronx-white.svg" alt="positronX.io Logo">
      </a>
    </nav>

    <!-- Sidebar navigation -->
    <div class="container-fluid">
      <div class="row">

        <nav class="col-md-2 d-md-block bg-light sidebar">
          <div class="sidebar-sticky">
            <ul class="nav flex-column">
              <li class="nav-item">
                <a class="nav-link active">
                  <i class="fas fa-user"></i>User Profile
                </a>
              </li>
              <!-- Calling SignOut() Api from AuthService -->
              <li class="nav-item">
                <a class="nav-link" (click)="authService.SignOut()">
                  <i class="fas fa-sign-out-alt"></i>Log out
                </a>
              </li>
            </ul>
          </div>
        </nav>

        <!-- Main content -->
        <main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-4">
          <div class="inner-adjust">

            <div class="pt-3 pb-2 mb-3 border-bottom">
              <h1 class="h2">User Profile</h1>
            </div>
            <!-- Show user data when logged in -->
            <div class="row" *ngIf="authService.userData as user">
              <div class="col-md-12">
                <div class="media">
                  <img class="align-self-start mr-5 img-thumbnail rounded-circle" src="{{(user.photoURL) ? user.photoURL : '/assets/dummy-user.png'}}"
                       alt="{{user.displayName}}">
                  <div class="media-body">
                    <h1>Hello: <strong>{{(user.displayName) ? user.displayName : 'User'}}</strong></h1>
                    <p>User ID: <strong>{{user.uid}}</strong></p>
                    <p>Email: <strong>{{user.email}}</strong></p>
                    <p>Email Verified: <strong>{{user.emailVerified}}</strong></p>
                  </div>
                </div>
              </div>
            </div>

          </div>
        </main>

      </div>
    </div>
  `,
  styles: []
})
export class DashboardComponent implements OnInit {

  constructor(public authService: AuthService) { }

  ngOnInit(): void {
  }

}

bene avviate il server:

ng server -o

provate a registrarvi con google, poi fate il login:

se tutto procede a dovere questo è il risultato, come potete notare viene importato anche l’avatar che utilizzate su google.

Potete scaricarvi le risorse dell’applicazione da Git, o se volete, potete vedere la demo.

Se volete Approfondire le conoscenze su Angular potete seguire il  corso completo su Udemy sempre scontato a 9.99/12.99 € , inoltre, nel momento in cui non foste soddisfatti, avete la possibilità di ottenere il rimborso completo dello stesso entro 30 giorni dalla data di acquisto!

Share and Enjoy !

0Shares
0 0

Chi è ?

Lucio Ticali è un Web & App developer con la passione per il web marketing,si occupa anche di tecniche di indicizzazione del sito e di promozione dello stesso (SEO e SEM).

Lascia la tua opinione