Подтвердить что ты не робот

Angular2 Функция canActivate() для вызова async

Я пытаюсь использовать защитные устройства маршрутизатора Angular2, чтобы ограничить доступ к некоторым страницам в моем приложении. Я использую Firebase Authentication. Чтобы проверить, вошел ли пользователь в систему Firebase, я должен вызвать .subscribe() объекта FirebaseAuth с обратным вызовом. Это код охранника:

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

При переходе на страницу с защитой на ней на консоль печатается authenticated или not authenticated (после некоторой задержки, ожидающей ответа от firebase). Однако навигация никогда не завершается. Кроме того, если я не зарегистрирован, я перенаправлен на маршрут /login. Таким образом, проблема, с которой я столкнулась, - return true, не отображает запрошенную страницу пользователю. Я предполагаю, что это потому, что я использую обратный вызов, но я не могу понять, как это сделать в противном случае. Любые мысли?

4b9b3361

Ответ 1

canActivate необходимо вернуть Observable, который завершает:

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

Отсутствует return, и я использую map() вместо subscribe(), потому что subscribe() возвращает Subscription not a Observable

Ответ 2

canActivate может возвращать Promise, который также решает a boolean

Ответ 3

Вы можете использовать Observable для обработки логической части async. Вот код, который я тестирую, например:

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