angular2:只获取和缓存一次令牌

时间:2017-02-22 11:57:59

标签: angular

我有一个“令牌”服务,它返回一个访问令牌。然后我有许多其他服务使用此服务来获取访问令牌,然后他们可以使用请求头中包含的令牌对后端进行API调用。

问题是这些服务中的许多服务几乎同时调用令牌服务,因此在第一次调用令牌服务之前已经“缓存”之前,下一次调用被触发了.. 。

导致对后端的多次调用并获得多个令牌。

有人可以告诉我如何停止对后端的多次调用。 或者如何在其他所有内容之前运行Token服务并缓存结果,然后才允许应用程序/服务运行/ bootstrap。

我正在使用棱角2.4.4

感谢任何帮助/建议

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

export class Token{

    private cachedTokenObject = {
        'tokenKey':false,
        'userName':"johndoe@gmail.com",
        '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);
                });
            }
        });
    }
}

2 个答案:

答案 0 :(得分:2)

我有类似的问题,我使用RxJs运算符解决了它。 这是我的解决方案:

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

postRequest负责检索刷新令牌。 请注意,它会返回一个可观察的内容。

在构造函数中,我创建了一个observable,它将推迟postRequest并分享我的observable:

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

共享运营商将在多个订户之间共享订阅。这有助于更好地理解它:RxJs - getting started

然后我创建了一个执行observable的方法:

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

您可以多次订阅refreshToken方法测试代码,然后计算浏览器发出的请求数:

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

希望这是有道理的。

答案 1 :(得分:0)

是否有任何阻止您将令牌存储在本地存储中的内容? ie window.localStorage.setItem('token_name', token);然后你的令牌服务可以有一个公共函数来检索令牌,如:

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

如果令牌不存在,则调用后端。至于在应用程序启动之前检索令牌,有很多方法可以根据您的体系结构来处理它。例如,在登录时,在导航到下一页之前将令牌存储在本地存储中。您还可以在路由上设置Guards以验证存储中是否存在令牌。

有一个很好的库可以处理自动将身份验证标头附加到名为Angular-JWT的Http请求。它还包含帮助函数来检查令牌过期。

希望有所帮助。