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
, не отображает запрошенную страницу пользователю. Я предполагаю, что это потому, что я использую обратный вызов, но я не могу понять, как это сделать в противном случае. Любые мысли?
Ответы
Ответ 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);
});
}
}
}