问题描述
如果当前访问令牌已过期,我正在尝试刷新访问令牌.
I am trying to refresh access token if current access token is expired.
我一次发送多个请求,并且希望创建一个队列,因此其他请求将不会请求刷新令牌路由.
I am sending multiple requests at one time and I want to make a kind of a queue, so other requests won't request refreshing token route.
我已经搜索了一些最佳实践和示例,并找到了针对Angular 6和rxjs v6的以下解决方案,它们使用了BehaviourSubject和switchMaps.(请参阅附件代码)
I've googled some best practises and examples and found out the following solution for Angular 6 and rxjs v6, which is using BehaviourSubject and switchMaps. (please see attached code)
但是我使用的是Angular 8(8.1)和rxjs v6.4,此解决方案不适用于我.
However I am using Angular 8 (8.1) and rxjs v6.4 and this solution does not work for me.
它根本无法到达 this.authService.requestAccessToken().pipe
中的 switchMap
.(使用console.log测试)
It simply does not reach switchMap
in this.authService.requestAccessToken().pipe
. (Tested using console.log)
但是,如果我发表评论返回this.refreshTokenSubject.pipe
并返回 next.handle(request)
,它将到达该switchMap,但其他请求失败.
However if I comment return this.refreshTokenSubject.pipe
and return next.handle(request)
it reaches that switchMap, but my other requests are failed.
您知道是否已更改任何内容,还是应该尝试以其他方式进行此操作?
Do you know if anything has been changed or should I try doing this in another way?
- 令牌拦截器
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
所以我用这些资料来编写我的拦截器:
UPD 1
So I used these sources to write my interceptor:
-
https://itnext.io/angular-tutorial-implement-refresh-token-with-httpinterceptor-bfa27b966f57 (Angular 4解决方案,我认为它附加在rxjs版本上)
https://itnext.io/angular-tutorial-implement-refresh-token-with-httpinterceptor-bfa27b966f57 (Angular 4 solution, I believe it edpends on rxjs version)
https://github.com/melcor76/interceptors/blob/master/src/app/interceptors/auth.interceptor.ts
我已经从拦截器范围中排除了 refresh
请求,现在它可以正常工作了感谢@JBNizet
I've excluded refresh
request from interceptor scope and now it's workingThanks to @JBNizet
推荐答案
我已经从拦截器范围中排除了刷新请求,现在它可以正常工作了.我已进行临时修复,以查看其以最快的方式运行.
I've excluded refresh request from interceptor scope and now it's working.I've made a temporary fix in order to see it's working in the fastest way.
现在我的TokenInterceptor看起来像:
Now my TokenInterceptor looks like:
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>> {
if (request.url.indexOf('refresh') !== -1) {
return next.handle(request);
}
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}`
}
});
}
}
感谢@JBNizet
Thanks to @JBNizet
这篇关于Angular 8拦截调用以刷新令牌的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!