FirebaseAuthを使用してAngular 2ルートのAuthGuardを構築しようとしています。
これは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;
}
});
}
}
ここでの問題は明らかに非同期です。サブスクリプションが「loggedIn」をtrueに変更するのに間に合うようにデータを受信しないため、AuthGuardのcanActivate()は常にfalse値を返します。
これを修正するためのベストプラクティスは何ですか?
編集:
オブザーバブルを返すように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);
.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);
}
新しいバージョンの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
からtake
、map
、およびdo
をインポートすることを忘れないでください。