21

Firebase Auth を使用して 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;
            }
        });
    }
}

ここでの問題は明らかに非同期です。AuthGuard の canActivate() は、「loggedIn」を true に変更するのに間に合うようにサブスクリプションがデータを受信しないため、常に false の値を返します。

これを修正するためのベストプラクティスは何ですか?

編集:

Observable を返すように 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);
4

3 に答える 3

11

.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);
  }
于 2016-09-19T00:14:21.863 に答える