AuthGuard не ждет завершения аутентификации перед проверкой пользователя

Я прочитал руководство здесь: https://angular.io/docs/ts/latest/guide/router.html

Кажется довольно простым, однако я не уверен, как использовать аутентификацию angularfire2 в пределах аутентификации (canActivate). Что я пробовал это:

AuthService

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

@Injectable()
export class AuthService {

  private user: any;

  constructor(private af: AngularFire) {
    this.af.auth.subscribe(user => {
      this.user = user;
    })
  }

  get authenticated(): boolean {
    return this.user ? true : false;
  }

}

AuthGuard

@Injectable()
export class AuthGuard implements CanActivate {

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

  canActivate(): Observable<boolean> | boolean {
    if (this.authService.authenticated)
      return true;

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

}

Я также добавил AuthService к поставщикам начальной загрузки.

Это нормально работает, однако моя главная проблема - когда я обновляю (или первоначально загружаю) страницу, на которой есть AuthGuard он всегда перенаправляет меня на страницу входа, так как AuthGuard не ждет ответа аутентификации Есть ли способ дождаться завершения аутентификации (даже если она не удалась), а затем проверить, прошел ли аутентификация пользователя?

3 ответа

Решение

Проблема с вашим кодом. В AuthGuard вы проверяете результат метода authenticated(), который, скорее всего, вернет false, поскольку свойство пользователя все еще не установлено. Попробуй это:

AuthService:

import { Injectable } from '@angular/core';
import { AngularFire } from 'angularfire2';';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class AuthService {

  private user: any;

  constructor(private af: AngularFire) { }
  setUser(user) { this.user = user; }
  getAuthenticated(): Observable<any> { return this.af.auth; }
}

AuthGuard:

@Injectable()
export class AuthGuard implements CanActivate {

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

  canActivate(): Observable<boolean> | boolean {
    // here check if this is first time call. If not return 
    // simple boolean based on user object from authService
    // otherwise:

    return this.authService.getAuthenticated.map(user => {
          this.authService.setUser(user);
          return user ? true : false;
    })

  } 
}

Это может отличаться в некоторых версиях маршрутизатора, но мне нужно было вернуть наблюдаемое, которое завершается.

import { CanActivate, Router } from '@angular/router'

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

  canActivate(): Observable<boolean> {
    return this.af.auth.map(user => {
      if (user != null)
        return true
      this.router.navigate(['/login'])
    })
    .take(1) // To make the observable complete after the first emission
  }
}

ОБНОВЛЕНИЕ 2021 для AngularFire, RXJS и Firebase

Взято из ответа Бауми

      **AuthService**:
import { Injectable } from '@angular/core';

import { AngularFireAuth } from '@angular/fire/auth';
import * as firebase from 'firebase/';

import { Observable } from 'rxjs';
    
@Injectable()
export class AuthService {

    private user: firebase.default.User;

    constructor(private afAuth: AngularFire) { }

    setUser(user) { 
        this.user = user; 
    }
    
    getAuthenticated(): Observable<firebase.default.User> { 
        return this.afAuth.user; 
        }
}


**AuthGuard**:
import { map } from 'rxjs/operators';

@Injectable()
export class AuthGuard implements CanActivate {

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

    canActivate(): Observable<boolean> {
        // here check if this is first time call. If not return 
        // simple boolean based on user object from authService
        // otherwise:

        return this.authService.getAuthenticated().pipe(
            map(user => {
                this.authService.setUser(user);
                return user ? true : false;
            })
        )
    } 
}
Другие вопросы по тегам