Angular2-ルーティング-CanActivateはObservableで動作します


94

私が持っているAuthGuard実装していること(ルーティングするために使用)CanActivateを

canActivate() {
    return this.loginService.isLoggedIn();
}

私の問題は、CanActivate-resultがhttp-get-resultに依存していることです-LoginServiceObservableを返します。

isLoggedIn():Observable<boolean> {
    return this.http.get(ApiResources.LOGON).map(response => response.ok);
}

それらをまとめるにはどうすればよいですか?CanActivateをバックエンドの状態に依存させますか?

######

編集:この質問は2016年のものであることに注意してください-角度/ルーターの非常に初期の段階が使用されています。

######


2
ここを読んだことがありますか?angle.io/docs/ts/latest/guide/router.htmlルートガードの検索CanActivateのAPIリファレンスは次のとおりです:angular.io/docs/ts/latest/api/router/index/…ご覧のとおり、どちらかを返すことができますbooleanまたはObservable <boolean>
mollwe 2016年

4
canActivate()を返すことができますObservableが、Observableが完了していることを確認してください(つまりobserver.complete())。
フィリップブリー2016

1
@PhilipBulleyオブザーバブルがより多くの値を出力してから完了するとどうなりますか?警備員は何をしますか?これまでに見たのはtake(1)、ストリームの完全性を実現するためのRx演算子の使用です。追加するのを忘れた場合はどうなりますか?
フェリックス

回答:


146

「@angular / router」を最新のものにアップグレードする必要があります。例:「3.0.0-alpha.8」

AuthGuard.tsを変更する

@Injectable()
export class AuthGuard implements CanActivate {
    constructor(private loginService:LoginService, private router:Router) { }

    canActivate(next:ActivatedRouteSnapshot, state:RouterStateSnapshot) {
        return this.loginService.isLoggedIn().map(e => {
            if (e) {
                return true;
            }
        }).catch(() => {
            this.router.navigate(['/login']);
            return Observable.of(false);
        });
    }   
}

ご不明な点がございましたら、お気軽にお問い合わせください!


3
これは非常によく似た方法でpromiseで機能することを指摘する価値があります。私の実装でisLoggedIn()は、がであると仮定するとPromise、次のことができます。isLoggedIn().then((e) => { if (e) { return true; } }).catch(() => { return false; });これが将来の旅行者に役立つことを願っています。
kbpontius 2017年

6
追加する必要がありましたimport 'rxjs/add/observable/of';
marc_aragones 2017年

1
今は良い答えではありませんIMO ..サーバー側で何が起こっているのか詳細を提供していません...アルファ版では古くなっています!...このベストプラクティスに準拠していません..angular.io / docs / ts / latest / guide / …..以下の更新された回答を参照してください(できれば1日上)
danday74 2017年

1
canActivateはObservable <boolean>を再調整する必要があります
Yoav Schniederman

大きな助け:)ありがとう
gschambial 2017

57

角度5とRxJS 5.5のKery胡の答えの更新作業が推奨されていませんが。ここで、catchError演算子をpipeおよびlettable演算子組み合わせて使用​​する必要がありますcatch

import { Injectable } from '@angular/core';
import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { catchError, map} from 'rxjs/operators';
import { of } from 'rxjs/observable/of';

@Injectable()
export class AuthGuard implements CanActivate {

  constructor(private loginService: LoginService, private router: Router) { }

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean>  {
    return this.loginService.isLoggedIn().pipe(
      map(e => {
        if (e) {
          return true;
        } else {
          ...
        }
      }),
      catchError((err) => {
        this.router.navigate(['/login']);
        return of(false);
      })
    );
  }   

}

isLoggedIn()の後にもう1つのXHR呼び出しがあり、XHRの結果が2番目のXHR呼び出しで使用されます。最初の結果を受け入れる2番目のajax呼び出しを行うにはどうすればよいですか?あなたが与えた例はとても簡単です、私が別のajaxも持っているなら、plsはpipe()の使い方を教えてくれますか?
Pratik

9

canActivate()Observable<boolean>戻り値として受け入れます。ガードは、Observableが解決して値を確認するのを待ちます。'true'の場合はチェックに合格し、そうでない場合(その他のデータまたはスローされたエラー)はルートを拒否します。

.map演算子を使用して、Observable<Response>を次のObservable<boolean>ように変換できます。

canActivate(){
    return this.http.login().map((res: Response)=>{
       if ( res.status === 200 ) return true;
       return false;
    });
}

1
キャッチブロックはどうですか?キャッチブロックは、401である場合に呼び出されますか?
danday74 2017年

1
角度4では機能しません。ジェネリック型を定義する場所が必要です。
gtzinos 2017年

2

私はこのようにそれをしました:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
return this.userService.auth(() => this.router.navigate(['/user/sign-in']));}

ご覧のとおり、http呼び出しが失敗した場合の対処方法をuserService.authにフォールバック関数を送信しています。

そしてuserServiceで私は持っています:

import 'rxjs/add/observable/of';

auth(fallback): Observable<boolean> {
return this.http.get(environment.API_URL + '/user/profile', { withCredentials: true })
  .map(() => true).catch(() => {
    fallback();
    return Observable.of(false);
  });}

.map()関数に関して本当に良い答え-本当に本当に良い:)-フォールバックコールバックを使用しませんでした-代わりにcanActivateメソッドでauthObservableをサブスクライブしました-アイデアに感謝します
danday74 2017年

0

これはあなたを助けるかもしれません

import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { Select } from '@ngxs/store';
import { Observable } from 'rxjs';
import { map, take } from 'rxjs/operators';
import { AuthState } from 'src/app/shared/state';

export const ROLE_SUPER = 'ROLE_SUPER';

@Injectable()
export class AdminGuard implements CanActivate {

 @Select(AuthState.userRole)
  private userRoles$: Observable<string[]>;

  constructor(private router: Router) {}

 /**
   * @description Checks the user role and navigate based on it
   */

 canActivate(): Observable<boolean> {
    return this.userRoles$.pipe(
      take(1),
      map(userRole => {
        console.log(userRole);
        if (!userRole) {
          return false;
        }
        if (userRole.indexOf(ROLE_SUPER) > -1) {
          return true;
        } else {
          this.router.navigate(['/login']);
        }
        return false;
      })
    );
  } // canActivate()
} // class

-1

CanActivateはObservableで機能しますが、CanActivate:[Guard1、Guard2]のように2つの呼び出しが行われると失敗します。
ここで、Guard1からObservable of falseを返すと、Guard2もチェックインされ、Guard2がtrueを返した場合にルートへのアクセスが許可されます。これを回避するには、Guard1はObservable ofbooleanではなくbooleanを返す必要があります。


-10

canActivate()では、ローカルブールプロパティを返すことができます(この場合、デフォルトはfalseです)。

private _canActivate: boolean = false;
canActivate() {
  return this._canActivate;
}

そして、LoginServiceの結果で、そのプロパティの値を変更できます。

//...
this.loginService.login().subscribe(success => this._canActivate = true);

あなたは天才です、サー。
Kien NguyenNgoc19年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.