【发布时间】:2016-09-26 10:41:14
【问题描述】:
我正在为使用访问令牌的 API 制作 Angular 2 前端。我正在尝试使用 observables 和 ngrx/store。
登录和注销工作正常且符合预期。我还编写了一些代码来处理由于令牌过期而导致请求失败的情况。这段代码通常可以正常工作,但是当我在短时间内有多个请求时会遇到麻烦。例如,当我刷新页面并且应用尝试填充整个应用所需的两个或三个商店时,就会发生这种情况。
我的身份验证服务具有以下功能:
refreshLogin(): Observable<any> {
const username = this.currentUser();
let query = new URLSearchParams();
query.set('refresh_token', this.refreshToken());
query.set('grant_type', 'refresh_token');
return this.getToken(username, query.toString());
}
private getToken(username: string, body: string): Observable<any> {
const url = Config.AUTH_TOKEN_PATH;
return this.http.post(url, body)
.map((res: Response) => res.json())
.do(
(data) => {
const token = {
username: username,
accessToken: data.access_token,
refreshToken: data.refresh_token,
tokenType: data.token_type,
expiresIn: data.expires_in
};
this.store.dispatch(AuthActions.loginSuccess(token));
},
error => {
const description = error.json().error_description;
this.store.dispatch(AuthActions.loginError(description));
console.error(error);
}
)
;
}
我的 REST 函数有这样一个函数:
get(url: string): Observable<any> {
return this.http.get(url, new RequestOptions({ headers: this.authHeader() }))
.catch(err => {
if (err.status === 401) {
return this.auth.refreshLogin()
.switchMap(() => this.http.get(url, new RequestOptions({ headers: this.authHeader() })))
.catch(err2 => err2);
} else {
console.log(err);
}
})
.map((res: Response) => res.json())
;
}
我不认为需要 currentUser()、refreshToken() 和 authHeader() 函数来理解我的问题。
如果我有一个失败的请求并且错误是 401,我的应用会调用 refreshLogin(),获取新的访问令牌并存储它,然后使用新的访问令牌再次尝试原始请求。
如果我有多个失败的请求,并且它们同时有效地发生,我就会遇到问题。例如,假设我有两个 GET 请求。它们都返回 401 错误。它们都触发了refreshLogin() 函数。一个refreshLogin() 成功并存储一个新的访问令牌;另一个失败,因为用于刷新的令牌不再有效。这个函数流现在失败了,导致我的应用程序停止。
一种解决方案是将我的 GET 请求串联堆叠,但似乎并非必须如此。
我觉得应该有一个解决方案,在失败的 GET(或其他)请求中,应用程序会触发刷新访问令牌的调用。 auth 服务会限制这些请求,因此每隔几秒或某事只能有一个。它满足了这个请求,并将新的访问令牌返回给所有请求以重试。
您认为这是一种明智的方法,还是我只是想修补一种一开始就被错误考虑的方法?您建议如何让这些部分交互?
【问题讨论】:
-
嘿伙计,你解决这个问题了吗?如果是,您是如何解决的,我遇到了与您相同的问题。谢谢!
-
嗨@SydneyLoteria。我确实解决了我的问题,谢谢。事实证明我的想法是正确的,但对 rxjs 的了解还不够,无法让它发挥作用。我使用
.throttleTime(3000)在三秒内停止了多个刷新请求。但是,我可能应该补充一点,我也使用了@ngrx/effects。所以它实际上是另一个被限制的可观察对象......然后该可观察对象调用refreshToken函数。我希望这是有道理的。 -
throttleTime 对我来说是新的 :)。所以你的意思是我会在 refreshToken 服务上添加 .throttleTime(3000) 如果它们被多次调用,这将导致停止所有活动的 refreshToken?
-
如果你可以给我一些例子的话。我对如何将它用于我的 refresh_token 服务的节流时间有点困惑。非常感谢!
-
我在我的实现中添加了一个答案。希望对您有所帮助。
标签: authentication angular angular2-observables