我有一个“令牌”服务,它返回一个访问令牌。然后我有许多其他服务使用此服务来获取访问令牌,然后他们可以使用请求头中包含的令牌对后端进行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);
});
}
});
}
}
答案 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请求。它还包含帮助函数来检查令牌过期。
希望有所帮助。