【发布时间】:2018-11-07 21:02:15
【问题描述】:
我需要在发出请求之前刷新 HttpInterceptor 中的令牌,为此我在请求之前检查访问令牌并在它过期时调用刷新。 目前,我的拦截器如下所示:
@Injectable()
export class TokenInterceptor implements HttpInterceptor {
private refreshTokenSubject = new BehaviorSubject(null);
private refreshTokenObservable = this.refreshTokenSubject.asObservable();
private isRefreshingToken = false;
constructor(private authService: AuthService) {
}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const tokenData = AuthService.getCurrentSessionData();
if (!this.isRefreshingToken) {
// if no token set - make request as-is
const tokenSet = tokenData && tokenData.token;
if (!tokenSet) {
return next.handle(request);
}
// proceed if token not expired
const tokenExpired = new Date(tokenData.expirationDate) < new Date();
if (!tokenExpired) {
return next.handle(this.setAuthHeader(request, tokenData.token));
}
// check if we can refresh the token and logout instantly if not
const tokenRefreshable = tokenData.refreshToken && new Date(tokenData.refreshTokenExpirationDate) > new Date();
if (!tokenRefreshable) {
this.authService.logout();
return Observable.throw('');
}
this.isRefreshingToken = true;
// make all subsequent requests wait for new token
this.refreshTokenSubject.next(null);
// make refresh request
return this.authService.refreshToken()
.switchMap((res: any) => {
AuthService.storeSessionData(res, Utils.getLocalStorageItem(STORAGE_KEYS.STAY_LOGGED_IN));
this.isRefreshingToken = false;
// let subsequent awaiting proceed
this.refreshTokenSubject.next(res.access_token);
return next.handle(this.setAuthHeader(request, res.access_token));
})
.catch((err) => {
this.authService.logout();
return Observable.throw('');
})
.finally(() => {
this.isRefreshingToken = false;
});
} else {
// if token refreshing in progress - wait for new token
return this.refreshTokenObservable
.filter(token => token !== null)
.take(1)
.switchMap((token) => {
return next.handle(this.setAuthHeader(request, token));
});
}
}
private setAuthHeader(request, token) {
return request.clone({
setHeaders: {
Authorization: `Bearer ${token}`,
},
});
}
}
问题是this.authService.refreshToken() 永远不会发出请求,并且后续请求永远不会继续。我猜是因为没有订阅从 HttpClient 返回的 observable,这里是 refreshToken 方法代码:
public refreshToken() {
const tokenData = AuthService.getCurrentSessionData();
return this.http.post(
`${environment.apiPath}/auth/refresh`,
{ refresh_token: tokenData.refreshToken },
);
}
如何修复此代码以发出 refreshToken 请求并让其他请求按预期继续执行?
【问题讨论】:
-
“this.authService.refreshToken() 从不发出请求” 拦截器阻止它这样做。
-
@abetteroliver 谢谢你,这是问题,太愚蠢了)
-
您是否编辑了您的帖子以修复错误并解决问题?问题出在哪里?是不是因为你没有对你的主拦截器进行特殊处理,所以它没有拦截刷新请求?
-
@KevinM,不,我认为我没有编辑问题,我通过在刷新令牌请求中传递
noIntercept标头并添加删除此标头并在拦截器中绕过请求的逻辑来解决问题
标签: javascript angular typescript rxjs angular-httpclient