16

我正在嘗試使用Firebase身份驗證爲Angular 2路由創建AuthGuard。Angular 2 AuthGuard + Firebase身份驗證

這是AuthGuard服務:

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

@Injectable() 
export class AuthGuard implements CanActivate { 

    constructor(private AuthService: AuthService, 
       private router: Router) {} 

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { 
    if (this.AuthService.loggedIn) { return true; } 

    this.router.navigate(['login']); 
    return false; 
    } 
} 

這是一個檢查,如果用戶登錄並綁定結果在其構造屬性「的loggedIn」的AuthService。

import { Injectable } from '@angular/core'; 
import { AngularFire } from 'angularfire2'; 
import { Router } from '@angular/router'; 

@Injectable() 
export class AuthService { 
loggedIn: boolean = false; 

    constructor(
    public af: AngularFire, 
    public router: Router) { 
     af.auth.subscribe(user => { 
      if(user){ 
       this.loggedIn = true; 
      } 
     }); 
    } 
} 

這裏的問題顯然是不同步的。 AuthGuard的canActivate()總是返回一個錯誤的值,因爲訂閱沒有及時收到數據將'loggedIn'更改爲true。

解決這個問題的最佳做法是什麼?

編輯:

更改AuthGuard返回一個可觀察。

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { 
    return this.af.auth.map((auth) => { 
     if (!auth) { 
      this.router.navigateByUrl('login'); 
      return false; 
     } 
     return true; 
    }); 
    } 

這種工作,因爲你沒有被重定向到登錄...但目標AuthGuarded組件不呈現。

不知道它是否與我的app.routes。這是該部分的代碼:

const routes: Routes = [ 
    { path: '', component: MainComponent, canActivate: [AuthGuard] }, 
    ... 
]; 

export const routing = RouterModule.forRoot(routes); 
+0

嗨!你可以做一個plunkr嗎? –

+0

@GuillaumeLeMière這將是相當困難的,因爲有涉及的Firebase身份驗證... – cerealex

回答

11

使用.take(1)完成可觀察事件以使組件呈現。

import {Observable} from "rxjs/Observable"; 
import 'rxjs/add/operator/map'; 
import 'rxjs/add/operator/take'; 

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { 
    return this.af.auth.map((auth) => { 
     if (!auth) { 
      this.router.navigateByUrl('login'); 
      return false; 
     } 
     return true; 
    }).take(1); 
    } 
+0

似乎升級到Angular 2.0.0後,我無法再使用map()。 Ts說''Property'map'不存在於'AngularFireAuth'類型中。 – cerealex

+0

我不得不添加導入'rxjs/add/operator/map'並導入'rxjs/add/operator/take'使其工作,但它畢竟可用。謝謝! – cerealex

+0

很高興爲你效勞。我應該提到進口產品,因爲我從RC5升級後有同樣的問題。 – codedesignr

1

對於AngularFire新版本,你必須使用authState代替:

@Injectable() 
export class AuthGuard implements CanActivate { 
    constructor(
    private afAuth: AngularFireAuth, 
    private router: Router 
) {} 

    canActivate(): Observable<boolean> { 
    return this.afAuth.authState 
     .take(1) 
     .map(authState => !!authState) 
     .do(auth => !auth ? this.router.navigate(['/login']) : true); 
    } 
} 

不要忘了從rxjs/add/operator進口takemapdo

+0

您節省了我的一天:) –