Функция 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 { 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
, не отображает запрошенную страницу пользователю. Я предполагаю, что это потому, что я использую обратный вызов, но я не могу понять, как это сделать в противном случае. Есть предположения?
- Угловой 2.0 маршрутизатор не работает при перезагрузке браузера
- Динамическая маршрутизация на основе внешних данных
- Как вернуться на предыдущую страницу
- Использование разрешения в Angular2 Routes
- Возможна ли уклон 2 объекта через параметры маршрута?
- Как определить, как пользователь перемещается обратно в Angular2?
- Как передать параметры запроса с помощью routerLink в новом Router V 3 alpha (владивосток)
- Как переключать макеты в Angular2
- Как получить текущий маршрут
- Предупреждать пользователя о несохраненных изменениях перед выходом на страницу
- Передача данных в дочерние компоненты маршрутизатора-выхода (угловые 2)
- Угловое redirect на страницу входа в систему
- Угловая ошибка 2: 404 возникает при обновлении через браузер
canActivate
необходимо вернуть Observable
который завершает:
@Injectable() export class AuthGuard implements CanActivate { constructor(private auth: AngularFireAuth, private router: Router) {} canActivate(route:ActivatedRouteSnapshot, state:RouterStateSnapshot):Observable|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
не Observable
canActivate
может возвращать Promise
которое также разрешает boolean
Вы можете использовать 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 { if (this.detailService.tempData) { return true; } else { console.log('loading...'); return new Observable ((observer) => { setTimeout(() => { console.log('done!'); this.detailService.tempData = [1, 2, 3]; observer.next(true); observer.complete(); }, 1000 * 5); }); } } }
Чтобы расширить самый популярный ответ. API Auth для AngularFire2 имеет некоторые изменения. Это новая подпись для достижения AngularFire2 AuthGuard:
import { Injectable } from '@angular/core'; import { Observable } from 'rxjs/Observable'; import { AngularFireAuth } from 'angularfire2/auth'; import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; @Injectable() export class AuthGuardService implements CanActivate { constructor( private auth: AngularFireAuth, private router : Router ) {} canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):Observable|boolean { return this.auth.authState.map(User => { return (User) ? true : false; }); } }
Примечание. Это довольно наивный тест. Вы можете заблокировать журнал экземпляра User, чтобы узнать, хотите ли вы протестировать его с более подробным аспектом пользователя. Но, по крайней мере, нужно защищать маршруты от пользователей, которые не вошли в систему.
Вы можете вернуть true | false в качестве обещания.
import {Injectable} from '@angular/core'; import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot} from '@angular/router'; import {Observable} from 'rxjs'; import {AuthService} from "../services/authorization.service"; @Injectable() export class AuthGuard implements CanActivate { constructor(private router: Router, private authService:AuthService) { } canActivate( next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable
в| Promise | boolean { return new Promise((resolve, reject) => { this.authService.getAccessRights().then((response) => { let result = response; let url = state.url.substr(1,state.url.length); if(url == 'getDepartment'){ if(result.getDepartment){ resolve(true); } else { this.router.navigate(['login']); resolve(false); } } }) }) } } import {Injectable} from '@angular/core'; import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot} from '@angular/router'; import {Observable} from 'rxjs'; import {AuthService} from "../services/authorization.service"; @Injectable() export class AuthGuard implements CanActivate { constructor(private router: Router, private authService:AuthService) { } canActivate( next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable
| Promise | boolean { return new Promise((resolve, reject) => { this.authService.getAccessRights().then((response) => { let result = response; let url = state.url.substr(1,state.url.length); if(url == 'getDepartment'){ if(result.getDepartment){ resolve(true); } else { this.router.navigate(['login']); resolve(false); } } }) }) } }