route canactivatechild canactivate authguard activate typescript angular angular2-routing

typescript - canactivatechild - Angular2 canActivate() llamando a la función asíncrona



canactivate route angular (6)

Estoy tratando de usar protectores de enrutador Angular2 para restringir el acceso a algunas páginas en mi aplicación. Estoy usando la autenticación de Firebase. Para verificar si un usuario ha iniciado sesión con Firebase, tengo que llamar a .subscribe() en el objeto FirebaseAuth con una devolución de llamada. Este es el código para el 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>|boolean { this.auth.subscribe((auth) => { if (auth) { console.log(''authenticated''); return true; } console.log(''not authenticated''); this.router.navigateByUrl(''/login''); return false; }); } }

Cuando se navega a una página que tiene la protección, authenticated o not authenticated se imprime en la consola (después de un retraso esperando la respuesta de firebase). Sin embargo, la navegación nunca se completa. Además, si no estoy conectado, soy redirigido a la ruta /login . Entonces, el problema que tengo es que return true no muestra la página solicitada al usuario. Supongo que esto se debe a que estoy utilizando una devolución de llamada, pero no puedo encontrar la manera de hacerlo de otra manera. ¿Alguna idea?


En la versión más reciente de AngularFire, el siguiente código funciona (relacionado con la mejor respuesta). Tenga en cuenta el uso del método "tubería".

import { Injectable } from ''@angular/core''; import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot} from ''@angular/router''; import {AngularFireAuth} from ''@angular/fire/auth''; import {map} from ''rxjs/operators''; import {Observable} from ''rxjs''; @Injectable({ providedIn: ''root'' }) export class AuthGuardService implements CanActivate { constructor(private afAuth: AngularFireAuth, private router: Router) { } canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean { return this.afAuth.authState.pipe( map(user => { if(user) { return true; } else { this.router.navigate([''/login'']); return false; } }) ); } }


Para ampliar en la respuesta más popular. La API de autenticación para AngularFire2 tiene algunos cambios. Esta es una nueva firma para lograr un AngularFire2 AuthGuard:

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>|boolean { return this.auth.authState.map(User => { return (User) ? true : false; }); } }

Nota: Esta es una prueba bastante ingenua. Puede consolar el registro de la instancia de Usuario para ver si desea probar con algún aspecto más detallado del usuario. Pero al menos debería ayudar a proteger las rutas contra los usuarios que no han iniciado sesión.


Puede devolver verdadero | falso como una promesa.

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<boolean> | Promise<boolean> | boolean { return new Promise((resolve, reject) => { this.authService.getAccessRights().then((response) => { let result = <any>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); } } }) }) } }


Puede usar Observable para manejar la parte lógica asíncrona. Aquí está el código que pruebo, por ejemplo:

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


canActivate necesita devolver un Observable que complete:

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

Falta un return y uso map() lugar de subscribe() porque subscribe() devuelve una Subscription no un Observable


canActivate puede devolver una Promise que resuelve un valor boolean también