2017-04-07 2 views
1

J'ai une situation très délicate dans mon application Angular 2. Dans mon service d'authentification, j'ai une fonction loggedIn qui lit le jeton d'accès jwt à partir du stockage local et vérifie si elle est expirée ou non et est utilisée pour faire passer les routes. Il est appelé à canActivate implémentations:Comment restreindre l'appel HTTP jusqu'à ce que le précédent soit terminé

canActivate(....):Observable<boolean>{ 
    return this.checkLogin(); 
} 

checkLogin():Observable<boolean>{ 
    return this._authSvc.isLoggedIn(); 
} 

///AUTHSERVICE 

isLoggedIn():Observable<boolean> { 
    let ex = tokenNotExpired('access_token'); 
    if (ex) { 
     let jwt = new JwtHelper(); 

     let t = jwt.decodeToken(localStorage['access_token']); 
     if (t.Id) { 
     this.Id = t.Id; 
     } 
    } 
    return Observable.of(new Boolean()).map(x => ex); 
} 

Récemment, je mis en œuvre la capacité de rafraîchir le jeton sur le back-end (ASP.Net Web API 2). Maintenant, l'idée est d'actualiser le jeton d'accès s'il a expiré en utilisant le jeton d'actualisation. J'ai essayé de l'aplomb de la méthode isLoggedIn. Si le jeton d'accès est expiré, je retournerai Observable<boolean> comme:

if(ex){ 
}else{ 
    return this.refreshToken();//<---NEW OBSERVABLE 
} 

ci-dessous de la fonction:

/*method to refresh the access token*/ 
refreshToken():Observable<boolean>{ 
    //setup stuff 
    var res= this.http.post(url,data,opts).map(r=> data=r.json()); 

    res.subscribe(data=>{ 
     localStorage['access_token'] = data.access_token; 
     localStorage['refresh_token'] = data.refresh_token; 
     let jwt = new JwtHelper(); 
     let t = jwt.decodeToken(localStorage['access_token']); 
     if (t.Id) { 
      this.Id = t.Id; 
     } 
    }, error=>{console.log(error); 
    }); 

    return res; 
} 

Mais cela crée tout l'enfer se déchaîner. Il y a des demandes sans fin qui échouent toutes (comme la première réinitialise le refresh token).

Ce que je veux faire est de faire une seule requête même si la fonction est déclenchée plusieurs fois de canActivate. Est-ce possible d'une manière ou d'une autre?

Répondre

0

Si cela ne vous dérange pas de stocker l'état de la requête en cours dans votre classe, cela pourrait être une option viable.

isPendingSubject: BehaviorSubject<boolean> = new BehaviorSubject(false); 
isPending$: Obserrvable<boolean> = this.isPendingSubject.asObservable(); 

/*method to refresh the access token*/ 
refreshToken():Obserrvable<boolean> { 
    //setup stuff 
    const refreshIsPending = this.isPendingSubject.value(); 
    if (this.refreshIsPending) return this.isPending$; 
    this.isPendingSubject.next(true); 
    this.refreshIsPending = true; 
    var res = this.http.post(url,data,opts).map(r=> data=r.json()); 

    res.subscribe(data=>{ 
     localStorage['access_token'] = data.access_token; 
     localStorage['refresh_token'] = data.refresh_token; 
     let jwt = new JwtHelper(); 
     let t = jwt.decodeToken(localStorage['access_token']); 
     if (t.Id) { 
      this.Id = t.Id; 
     } 
     this.isPendingSubject.next(false); 
    }, error=>{console.log(error); 
    }); 
    return res; 
} 
+0

Oui, j'avais réfléchi à cela et même essayé, mais comme je devais retourner 'Observable ' pour être consommé jusqu'à la chaîne, il change les choses simples 'return' ne fonctionnera pas. – TheVillageIdiot

+0

Je ne suis pas sûr de ce que vous voulez dire. Faites-vous quelque chose avec l'abonnement retourné? –

+0

Oui, il est utilisé dans 'CanActivate' finalement. – TheVillageIdiot

0

Depuis votre problème partage essentiellement un abonnement unique parmi plusieurs abonnés, vous pouvez garder le Observable dans une propriété et il suffit d'utiliser l'opérateur share() pour éviter de faire plusieurs appels this.http.post().

private refresh$: Observable; 

refreshToken(): Observable<boolean> { 
    if (!this.refresh$) { 
     this.refresh$ = this.http.post(url,data,opts) 
      .map(r=> data=r.json()) 
      .share(); 

     this.refresh$.subscribe(...); 
    } 

    return this.refresh$; 
} 

Je n'ai évidemment pas testé, mais j'espère que vous avez compris. Lorsque vous appelez la méthode plusieurs fois, vous recevez toujours le même Observable et l'opérateur share() s'assure qu'il n'y a toujours qu'un seul reqeust HTTP actif à ce moment.

+0

Eh bien, non ... J'avais «partage» là mais j'ai encore des demandes sans fin! laissez-moi essayer encore avec 'refresh $' – TheVillageIdiot

+0

@TheVillageIdiot Alors vous faites quelque chose de mal :) – martin

+0

bien peut-être. mais 'Observable' n'est pas autorisé sans' argument de type'. S'il est mis comme 'Observable ' subscribe obtient un 'boolean' au lieu de' data' de la fonction 'map' :( – TheVillageIdiot