【发布时间】:2020-07-21 20:57:43
【问题描述】:
如果当前访问令牌已过期,我正在尝试刷新访问令牌。
我一次发送多个请求,我想做一个队列,所以其他请求不会请求刷新令牌路由。
我在谷歌上搜索了一些最佳实践和示例,并找到了以下针对 Angular 6 和 rxjs v6 的解决方案,它使用了 BehaviourSubject 和 switchMaps。 (请看附件代码)
但是我使用的是 Angular 8 (8.1) 和 rxjs v6.4,这个解决方案对我不起作用。
它根本无法到达this.authService.requestAccessToken().pipe 中的switchMap。 (使用 console.log 测试)
但是,如果我评论 return this.refreshTokenSubject.pipe 并返回 next.handle(request),它会到达那个 switchMap,但我的其他请求都失败了。
您知道是否有任何更改或我应该尝试以其他方式进行更改吗?
- 令牌拦截器
import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { AuthService } from './auth.service';
import { Observable, BehaviorSubject, Subject } from 'rxjs';
import { switchMap, take, filter } from 'rxjs/operators';
@Injectable()
export class TokenInterceptor implements HttpInterceptor {
private refreshTokenInProgress = false;
private refreshTokenSubject: Subject<any> = new BehaviorSubject<any>(null);
constructor(public authService: AuthService) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const accessExpired = this.authService.isAccessTokenExpired();
const refreshExpired = this.authService.isRefreshTokenExpired();
if (accessExpired && refreshExpired) {
return next.handle(request);
}
if (accessExpired && !refreshExpired) {
if (!this.refreshTokenInProgress) {
this.refreshTokenInProgress = true;
this.refreshTokenSubject.next(null);
return this.authService.requestAccessToken().pipe(
switchMap((authResponse) => {
this.authService.saveToken(AuthService.TOKEN_NAME, authResponse.accessToken);
this.authService.saveToken(AuthService.REFRESH_TOKEN_NAME, authResponse.refreshToken);
this.refreshTokenInProgress = false;
this.refreshTokenSubject.next(authResponse.refreshToken);
return next.handle(this.injectToken(request));
}),
);
} else {
return this.refreshTokenSubject.pipe(
filter(result => result !== null),
take(1),
switchMap((res) => {
return next.handle(this.injectToken(request))
})
);
}
}
if (!accessExpired) {
return next.handle(this.injectToken(request));
}
}
injectToken(request: HttpRequest<any>) {
const token = this.authService.getToken(AuthService.TOKEN_NAME);
return request.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
}
}
- requestAccessToken
requestAccessToken(): Observable<any> {
const refreshToken = this.getToken(AuthService.REFRESH_TOKEN_NAME);
return this.http.post(`${this.basePath}/auth/refresh`, { refreshToken });
}
UPD 1
所以我使用这些资源来编写我的拦截器:
https://itnext.io/angular-tutorial-implement-refresh-token-with-httpinterceptor-bfa27b966f57(Angular 4 解决方案,我相信它依赖于 rxjs 版本)
https://github.com/melcor76/interceptors/blob/master/src/app/interceptors/auth.interceptor.ts
UPD 2
我已经从拦截器范围中排除了 refresh 请求,现在它正在工作
感谢@JBNizet
【问题讨论】:
-
我的猜测是 authService 发送一个 http 请求以获取刷新的令牌。所以这个http请求被这个拦截器拦截了。并且由于正在进行刷新,因此在刷新令牌之前无法发送用于获取刷新令牌的请求。您不应该像其他请求一样过滤尝试刷新令牌的请求。
-
@JBNizet 刚刚排除了该请求,似乎现在一切正常,非常感谢,你让我很开心。有时我们需要重新审视我们的代码。
-
你应该用解释和用于修复它的代码来回答你自己的问题。
标签: angular rxjs angular8 angular-http-interceptors refresh-token