2017-04-07 24 views
1

我的Angular 2應用程序中有一個非常棘手的情況。在我的身份驗證服務中,我有一個功能loggedIn,它從本地存儲中讀取jwt訪問令牌,並檢查它是否過期並用於關閉路由。這就是所謂的canActivate實現:如何限制HTTP呼叫,直到前一個完成

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

最近,我實現了刷新在後端(ASP.Net Web API 2)令牌的能力。現在,想法是刷新訪問令牌,如果它使用刷新令牌過期。我試圖從isLoggedIn方法中找到它。從下面的功能

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

:如果訪問令牌過期,我將返回Observable<boolean>作爲

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

但是,這是造成所有的地獄衝出重圍。有無數請求全部失敗(因爲第一個請求重置refresh token)。

我想要做的是隻發出一個請求,即使該功能從canActivate多次觸發。它有可能以任何方式?

回答

0

如果你不介意在你的班級中存儲當前請求的狀態,這可能是一個可行的選擇。

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

是的,我已經仔細考慮過,甚至嘗試過,但因爲我需要返回'Observable '來消耗鏈條,它改變了簡單的事情'return'不起作用。 – TheVillageIdiot

+0

我不確定你的意思。你正在做什麼與返回的訂閱? –

+0

是的,它最終用於'CanActivate'。 – TheVillageIdiot

0

由於您的問題基本上共享多個用戶之間的一個訂閱,你可以保持可觀察的性質,只是使用share()操作,以避免使多個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$; 
} 

我明顯沒有測試它,但我希望你明白這一點。當您多次調用該方法時,您始終會收到相同的Observable,並且運營商確保當時始終只有一個活動的HTTP請求。

+0

呃,不......我在那裏有'分享',但仍有無盡的要求!讓我再試'刷新$' – TheVillageIdiot

+0

@TheVillageIdiot然後你做錯了什麼:) – martin

+0

嗯,也許。但'Observable'沒有'type argument'是不允許的。如果它被設置爲'Observable ''subscribe'從'map'函數獲取一個'boolean'而不是'data' :( – TheVillageIdiot