2016-07-17 164 views
23

Sto cercando di utilizzare le protezioni 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'oggetto FirebaseAuth con un callback. Questo è il codice per la guardia:Angular2 canActivate() chiamata funzione asincrona

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>|boolean { 
     this.auth.subscribe((auth) => { 
      if (auth) { 
       console.log('authenticated'); 
       return true; 
      } 
      console.log('not authenticated'); 
      this.router.navigateByUrl('/login'); 
      return false; 
     }); 
    } 
} 

Quando un passare a una pagina che ha la guardia su di esso, sia authenticated, o not authenticated viene stampato sulla console (con un certo ritardo in attesa della risposta da Firebase). Tuttavia, la navigazione non è mai completata. Inoltre, se non sono connesso, vengo reindirizzato alla rotta /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?

+0

import Osservabile come questo -> import {Observable} da 'rxjs/Observable'; –

risposta

50

canActivate deve restituire un Observable che completa:

@Injectable() 
export class AuthGuard implements CanActivate { 

    constructor(private auth: AngularFireAuth, private router: Router) {} 

    canActivate(route:ActivatedRouteSnapshot, state:RouterStateSnapshot):Observable<boolean>|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'è una return manca e io uso map() invece di subscribe() perché subscribe() restituisce un non Subscription un Observable

+0

puoi mostrare come usare questa classe in altri componenti? –

+0

Non sai cosa intendi. Lo usi con rotte, non con componenti. Vedi https://angular.io/docs/ts/latest/guide/router.html#!#guards –

+0

L'Observable non viene eseguito nel mio caso. Non vedo alcuna uscita della console. Tuttavia, se restituisco booleani in modo condizionale (come nella documentazione) viene registrata la console. Questo è un semplice osservabile? – cortopy

5

canActivate può restituire un Promise che risolve anche boolean

1

È possibile utilizzare Observable per gestire la parte logica asincrona. Ecco il codice I test per 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<boolean> { 
    if (this.detailService.tempData) { 
     return true; 
    } else { 
     console.log('loading...'); 
     return new Observable<boolean>((observer) => { 
     setTimeout(() => { 
      console.log('done!'); 
      this.detailService.tempData = [1, 2, 3]; 
      observer.next(true); 
      observer.complete(); 
     }, 1000 * 5); 
     }); 
    } 
    } 
}