Angular2 canActivate () chiama la funzione asincrona

Sto cercando di utilizzare le guardie del router Angular2 per limitare l’accesso ad alcune pagine nella mia app. Sto usando l’autenticazione Firebase. Per verificare se un utente ha effettuato l’accesso con Firebase, devo chiamare .subscribe() sull’object FirebaseAuth con un callback. Questo è il codice per la guardia:

 import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import { AngularFireAuth } from "angularfire2/angularfire2"; import { Injectable } from "@angular/core"; import { Observable } from "rxjs/Rx"; @Injectable() export class AuthGuard implements CanActivate { constructor(private auth: AngularFireAuth, private router: Router) {} canActivate(route:ActivatedRouteSnapshot, state:RouterStateSnapshot):Observable|boolean { this.auth.subscribe((auth) => { if (auth) { console.log('authenticated'); return true; } console.log('not authenticated'); this.router.navigateByUrl('/login'); return false; }); } } 

Quando si naviga verso una pagina che ha la guardia su di essa, authenticated o not authenticated viene stampato sulla console (dopo qualche ritardo in attesa della risposta da Firebase). Tuttavia, la navigazione non è mai completata. Inoltre, se non sono connesso, vengo reindirizzato al percorso /login . Quindi, il problema che sto avendo è return true non mostra la pagina richiesta all’utente. Suppongo che ciò avvenga perché sto utilizzando una richiamata, ma non sono in grado di capire come farlo altrimenti. qualche idea?

canActivate deve restituire un Observable che completi:

 @Injectable() export class AuthGuard implements CanActivate { constructor(private auth: AngularFireAuth, private router: Router) {} canActivate(route:ActivatedRouteSnapshot, state:RouterStateSnapshot):Observable|boolean { return this.auth.map((auth) => { if (auth) { console.log('authenticated'); return true; } console.log('not authenticated'); this.router.navigateByUrl('/login'); return false; }).first(); // this might not be necessary - ensure `first` is imported if you use it } } 

C’è un return mancante e io uso map() invece di subscribe() perché subscribe() restituisce una Subscription non Observable

canActivate può restituire una Promise che risolve anche un boolean

È ansible utilizzare Observable per gestire la parte logica asincrona. Ecco il codice che collaudo ad esempio:

 import { Injectable } from '@angular/core'; import { CanActivate } from '@angular/router'; import { Observable } from 'rxjs/Observable'; import { DetailService } from './detail.service'; @Injectable() export class DetailGuard implements CanActivate { constructor( private detailService: DetailService ) {} public canActivate(): boolean|Observable { if (this.detailService.tempData) { return true; } else { console.log('loading...'); return new Observable((observer) => { setTimeout(() => { console.log('done!'); this.detailService.tempData = [1, 2, 3]; observer.next(true); observer.complete(); }, 1000 * 5); }); } } } 

Per espandere la risposta più popolare. L’API di autenticazione per AngularFire2 presenta alcune modifiche. Questa è una nuova firma per ottenere un AuthGuard AngularFire2:

 import { Injectable } from '@angular/core'; import { Observable } from 'rxjs/Observable'; import { AngularFireAuth } from 'angularfire2/auth'; import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; @Injectable() export class AuthGuardService implements CanActivate { constructor( private auth: AngularFireAuth, private router : Router ) {} canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):Observable|boolean { return this.auth.authState.map(User => { return (User) ? true : false; }); } } 

Nota: questo è un test abbastanza ingenuo. È ansible configurare la registrazione dell’istanza utente per vedere se si desidera testare alcuni aspetti più dettagliati dell’utente. Ma dovrebbe almeno contribuire a proteggere i percorsi contro utenti che non hanno effettuato l’accesso.

Puoi restituire true | false come una promise.

 import {Injectable} from '@angular/core'; import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot} from '@angular/router'; import {Observable} from 'rxjs'; import {AuthService} from "../services/authorization.service"; @Injectable() export class AuthGuard implements CanActivate { constructor(private router: Router, private authService:AuthService) { } canActivate( next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable | Promise | boolean { return new Promise((resolve, reject) => { this.authService.getAccessRights().then((response) => { let result = response; let url = state.url.substr(1,state.url.length); if(url == 'getDepartment'){ if(result.getDepartment){ resolve(true); } else { this.router.navigate(['login']); resolve(false); } } }) }) } }