2017-02-22 4 views
0

Ich habe einen "Token" Dienst, der ein Access-Token zurückgibt. Dann habe ich viele andere Dienste, die diesen Dienst verwenden, um ein Zugriffstoken zu erhalten, bevor sie einen API-Aufruf an das Back-End mit dem Token, das in dem Anforderungsheader enthalten ist, vornehmen können.angular2: get und Cache-Token nur einmal

Das Problem ist, dass viele dieser Dienste fast gleichzeitig die Token Dienst anrufen, so vor dem ersten Aufruf der Tokendienst zurückgekehrt und wurde als „Cache“ der nächste Anruf ausgelöst wird ...

Ergebnis in mehreren Aufrufen an das Back-End und Erhalt mehrerer Token.

Kann mir bitte jemand sagen, wie man die mehrfachen Anrufe zum Backend stoppt. Oder wie Sie den Token-Dienst vor allem anderen ausführen und das Ergebnis zwischenspeichern und erst dann zulassen, dass die Anwendung/Dienste/bootstrap ausführen.

Ich bin Winkel Verwendung 2.4.4

Jede Hilfe/Anregung geschätzt


import {Injectable} from '@angular/core'; 
import {Http} from '@angular/http'; 
import 'rxjs/add/operator/toPromise'; 

export class Token{ 

    private cachedTokenObject = { 
     'tokenKey':false, 
     'userName':"[email protected]", 
     'password':"1234", 
     'applicationId':"12344" 
    }; 

    constructor(private _http: Http){} 

    getAccessToken():Promise<Object>{ 

     if(this.cachedTokenObject.tokenKey){ 
      console.log("returning chached token"); 
      return Promise.resolve(this.cachedTokenObject); 
     }else{ 
      console.log("getting new token..."); 

      const tokenHeaders = "username=" + this.cachedTokenObject.userName + "&password=" + this.cachedTokenObject.password +"&grant_type=password"; 

      return this._http.post("https://someurl.com", tokenHeaders) 
      .toPromise() 
      .then(result => { 
       if(result.json().hasOwnProperty('access_token')){     
        this.cachedTokenObject.tokenKey = result.json()['access_token']; 
        return this.cachedTokenObject; 
       }else{ 
        console.log('"access_token" property not found in access object'); 
        return {}; 
       } 
      }) 
      .catch(error =>{ 
       console.error('*** getAccessToken error ***', error); 
       Promise.reject(error); 
      }); 
     } 
    } 
} 

import {Injectable} from '@angular/core'; 
import {Http} from '@angular/http'; 
import 'rxjs/add/operator/toPromise'; 
import { Headers, RequestOptions } from '@angular/http'; 
import {AccessTokenService} from './access-token.service'; 

@Injectable() 
export class LanguageService{ 

    private cachedLanguages:any; 

    constructor(private _http: Http, private _accessTokenService:AccessTokenService){} 

    getLanguages(){ 

     return this._accessTokenService.getAccessToken().then(token => { 

      if(this.cachedLanguages){ 
       console.log('returning cached languages', this.cachedLanguages); 
       return Promise.resolve(this.cachedLanguages); 
      }else{ 

       let headers = new Headers({ 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + token['tokenKey']}); 
       let options = new RequestOptions({ headers: headers }); 

       return this._http.get('https://someUrl/languages', options) 
       .toPromise() 
       .then(resp => { 
        this.cachedLanguages = JSON.parse(resp.json()); 

        return this.cachedLanguages; 
       }) 
       .catch(error =>{ 
        console.error('*** LanguageService error ***', error); 
        Promise.reject(error); 
       }); 
      } 
     }); 
    } 
} 
+0

http://stackoverflow.com/questions/36271899/what-ist-the-correct-way-to-share-the-result-of-an-angular-2-http-network-call-in/36291681 # 36291681 –

+0

@ Günter Zöchbauer, danke, dein Beispiel ist sehr klar und einfach zu verstehen – Khaled

Antwort

2

Ich hatte ein ähnliches Problem, und ich löste es mit RxJs-Operatoren. Hier ist meine Lösung:

private postRequest(): Observable<any> { 
    let data: URLSearchParams = new URLSearchParams(); 
    let obs = this.http.postWithHeaders(
     'token', data, { 'Content-Type': 'application/x-www-form-urlencoded' }) 
     .map((response) => { 
      ... 
     }) 
     .catch((error) => { 
      ... 
     }); 
    return obs; 
} 

Die postRequest ist verantwortlich für ein Aktualisierungs-Token abgerufen werden. Es ist wichtig zu beachten, dass es eine Observable zurückgibt.

Im Konstruktor erstelle ich einen beobachtbaren, die die postRequest verschieben wird, und ich meine beobachtbaren teilen:

this.source = Observable.defer(() => { 
     return this.postRequest(); 
    }).share(); 

Der Anteil Betreiber teilen sich das Abonnement zwischen mehreren Teilnehmern.Hier ist ein sehr nützlich, um besser zu verstehen, es: RxJs - getting started

ich dann ein Verfahren geschaffen, das die beobachtbare ausführt:

refreshToken(): Observable<any> { 
    return this.source 
     .do((data) => { 
      //extract the access token and save it to local storage 
     }, error => { 
      ... 
     }); 
} 

Sie den Code durch den Abschluss der refreshToken Methode mehrfach testen und dann Zählen der Anzahl der fragt der Browser macht:

this.tokenRefreshService.refreshToken().subscribe(x=>{...}) 
this.tokenRefreshService.refreshToken().subscribe(x=>{...}) 
this.tokenRefreshService.refreshToken().subscribe(x=>{...}) 

Hoffnung, die Sinn macht.

0

Gibt es etwas verhindert, dass Sie das Token in lokalen Speicher speichern ? dh window.localStorage.setItem('token_name', token); Und dann könnte Ihr Token Service haben eine öffentliche Funktion des Tokens, so etwas wie abzurufen:

retrieveToken() { return window.localStorage.getItem(tokenName); }

Wenn das Token nicht existiert, dann einen Anruf an das Backend machen. Wie beim Abrufen des Tokens vor dem Start der Anwendung gibt es zahlreiche Möglichkeiten, dies abhängig von Ihrer Architektur zu behandeln. Speichern Sie das Token beispielsweise nach der Anmeldung im lokalen Speicher, bevor Sie zur nächsten Seite navigieren. Sie können auch Guards auf Ihren Routen einrichten, um zu überprüfen, ob ein Token im Speicher vorhanden ist.

Es gibt eine nette Bibliothek zum automatischen Anhängen Ihres Authentifizierungsheaders an HTTP-Anfragen namens Angular-JWT. Es enthält auch Hilfsfunktionen, um den Tokenablauf zu überprüfen.

Hoffe, dass hilft.

+0

Ich denke, dass Khaled besorgt ist, dass mehrere gleichzeitige Anfragen gemacht werden, wenn es kein Token gibt. –

+0

@ Stely000, ja genau – Khaled

+0

Es wurde Ihnen gerade klar, dass Sie auf einen Fall stoßen, in dem Ihr Token gültig ist, wenn Sie es überprüfen, aber abläuft, bevor Sie die Anfrage stellen. Ich empfehle, einige Retry-Logik zu implementieren, um diese Race-Bedingung gerecht zu werden. –