web-dev-qa-db-fra.com

Angular 2 - Routing - CanActivate Work avec Observable

J'ai un AuthGuard (utilisé pour le routage) qui implémente CanActivate .

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

Mon problème est que le résultat CanActivate dépend d'un résultat http-get-result - le LoginService retourne un Observable .

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

Comment puis-je les réunir - faire en sorte que CanActivate dépende d'un état backend?

57
Philipp

Vous devez mettre à niveau "@ angular/router" vers la dernière version. par exemple "3.0.0-alpha.8" 

modifier 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);
        });
    }   
}

Si vous avez des questions, demandez moi!

109
Kery Hu

Mise à jour de la réponse de Kery Hu pour Angular 5 et RxJS 5.5 où l'opérateur catch est obsolète. Vous devez maintenant utiliser l'opérateur catchError avec les opérateurs pipe and ableable .

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);
      })
    );
  }   

}
21
Derek Hill

canActivate () accepte Observable<boolean> en tant que valeur renvoyée. Le gardien attendra que l’Observable soit résolu et examinera la valeur. Si 'true', la vérification est réussie, sinon (toute autre donnée ou erreur renvoyée) rejettera l'itinéraire. 

Vous pouvez utiliser l'opérateur .map pour transformer le Observable<Response> en Observable<boolean> comme suit:

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

Je l'ai fait de cette façon:

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

Comme vous pouvez le constater, j'envoie une fonction de secours à userService.auth que faire en cas d'échec de l'appel http.

Et dans userService, j'ai:

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);
  });}
2

Comment cela fonctionne-t-il pour vous sans avoir à appeler subscribe? Pour moi, lorsque j'appelle cela via mon API .net, rien ne revient. Je dois appeler abonnez-vous à mon service de garde d'authentification comme ceci, alors seulement, elle appelle réellement l'API . Mais puisque l'abonnement est asynchrone, ma protection de canActivate ne fonctionne pas et l'utilisateur peut accéder à la page.

AuthGauard service:

canActivate() { this.loginService.isLoggedIn()
      .subscribe(response => {
          if (!response) return false;})
return true;
}

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

Cela peut vous aider 

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
0
Kalanka