I am trying to use Angular2 router guards to restrict access to some pages in my app.  I am using Firebase Authentication.  In order to check if a user is logged in with Firebase, I have to call .subscribe() on the FirebaseAuth object with a callback.  This is the code for the guard:
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;         });     } }   When a navigate to a page that has the guard on it, either authenticated, or not authenticated is printed to the console (after some delay waiting for the response from firebase).  However, the navigation is never completed.  Also, if I am not logged in I am redirected to the /login route.  So, the issue I am having is return true doesn't display the requested page to the user.  I'm assuming this is because I am using a callback, but I am unable to figure out how to do it otherwise.  Any thoughts?
canActivate needs to return an Observable that completes:
@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     } }   There is a return missing and I use map() instead of subscribe() because subscribe() returns a Subscription not an Observable
You might use Observable to handle the async logic part. Here is the code I test for example: 
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);       });     }   } } 
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With