Angular 5 HttpClient拦截器JWT刷新令牌无法捕获401并重试我的请
|
我正在尝试实现401响应的捕获并尝试获取基于
Angular 4 Interceptor retry requests after token refresh的刷新令牌.我试图实现相同的事情,但我从来没有能够重试该请求,我真的不确定这是否是最好的应用刷新令牌策略的方法.
这是我的代码: @Injectable()
export class AuthInterceptorService implements HttpInterceptor {
public authService;
refreshTokenInProgress = false;
tokenRefreshedSource = new Subject();
tokenRefreshed$= this.tokenRefreshedSource.asObservable();
constructor(private router: Router,private injector: Injector) { }
authenticateRequest(req: HttpRequest<any>) {
const token = this.authService.getToken();
if (token != null) {
return req.clone({
headers: req.headers.set('Authorization',`Bearer ${token.access_token}`)
});
}
else {
return null;
}
}
refreshToken() {
if (this.refreshTokenInProgress) {
return new Observable(observer => {
this.tokenRefreshed$.subscribe(() => {
observer.next();
observer.complete();
});
});
} else {
this.refreshTokenInProgress = true;
return this.authService.refreshToken()
.do(() => {
this.refreshTokenInProgress = false;
this.tokenRefreshedSource.next();
}).catch(
(error) => {
console.log(error);
}
);
}
}
intercept(request: HttpRequest<any>,next: HttpHandler): Observable<HttpEvent<any>> {
this.authService = this.injector.get(AuthenticationService);
request = this.authenticateRequest(request);
return next.handle(request).do((event: HttpEvent<any>) => {
if (event instanceof HttpResponse) {
// do stuff with response if you want
}
},(err: any) => {
if (err instanceof HttpErrorResponse) {
if (err.status === 401) {
return this.refreshToken()
.switchMap(() => {
request = this.authenticateRequest(request);
console.log('*Repeating httpRequest*',request);
return next.handle(request);
})
.catch(() => {
return Observable.empty();
});
}
}
});
}
}
问题是从未到达过SwitchMap … if (err.status === 401) {
return this.refreshToken()
.switchMap(() => {
以及do操作符…… return this.authService.refreshToken()
.do(() => {
所以我带到了我的authService refreshToken方法…… refreshToken() {
let refreshToken = this.getToken();
refreshToken.grant_type = 'refresh_token';
refreshToken.clientId = environment.appSettings.clientId;
return this.apiHelper.httpPost(url,refreshToken,null)
.map
(
response => {
this.setToken(response.data,refreshToken.email);
return this.getToken();
}
).catch(error => {
return Observable.throw('Please insert credentials');
});
}
}
它返回一个映射的observable,我知道如果我替换了do in,它需要订阅… return this.authService.refreshToken()
.do(() => {
有了订阅我会打破可观察链.我很迷茫,而且我已经玩了很久没有解决方案了. :d
我很高兴你喜欢我的解决方案.我将在这里提出最终的解决方案,但是如果有人想知道我休闲的过程请到这里:
Refresh Token OAuth Authentication Angular 4+
好的,首先我创建了一个服务来保存刷新令牌请求的状态,并创建了Observable来知道请求何时完成. 这是我的服务: @Injectable()
export class RefreshTokenService {
public processing: boolean = false;
public storage: Subject<any> = new Subject<any>();
public publish(value: any) {
this.storage.next(value);
}
}
这是用于刷新令牌的拦截器: @Injectable()
export class RefreshTokenInterceptor implements HttpInterceptor {
constructor(private injector: Injector,private tokenService: RefreshTokenService) {
}
intercept(request: HttpRequest<any>,next: HttpHandler): Observable<HttpEvent<any>> {
const auth = this.injector.get(OAuthService);
if (!auth.hasAuthorization() && auth.hasAuthorizationRefresh() && !this.tokenService.processing && request.url !== AUTHORIZE_URL) {
this.tokenService.processing = true;
return auth.refreshToken().flatMap(
(res: any) => {
auth.saveTokens(res);
this.tokenService.publish(res);
this.tokenService.processing = false;
return next.handle(request);
}
).catch(() => {
this.tokenService.publish({});
this.tokenService.processing = false;
return next.handle(request);
});
} else if (request.url === AUTHORIZE_URL) {
return next.handle(request);
}
if (this.tokenService.processing) {
return this.tokenService.storage.flatMap(
() => {
return next.handle(request);
}
);
} else {
return next.handle(request);
}
}
}
所以在这里我等待刷新令牌可用或失败,然后我发布需要授权头的请求. 这是放置授权标头的拦截器: @Injectable()
export class TokenInterceptor implements HttpInterceptor {
constructor(private injector: Injector) {}
intercept(request: HttpRequest<any>,next: HttpHandler): Observable<HttpEvent<any>> {
const auth = this.injector.get(OAuthService);
let req = request;
if (auth.hasAuthorization()) {
req = request.clone({
headers: request.headers.set('Authorization',auth.getHeaderAuthorization())
});
}
return next.handle(req).do(
() => {},(error: any) => {
if (error instanceof HttpErrorResponse) {
if (error.status === 401) {
auth.logOut();
}
}
});
}
}
我的主要模块是这样的: @NgModule({
imports: [
...,HttpClientModule
],declarations: [
...
],providers: [
...
OAuthService,AuthService,RefreshTokenService,{
provide: HTTP_INTERCEPTORS,useClass: RefreshTokenInterceptor,multi: true
},useClass: TokenInterceptor,multi: true
}
],bootstrap: [AppComponent]
})
export class AppModule {
}
请欢迎任何反馈,如果我有什么不妥,请告诉我.我正在使用Angular 4.4.6进行测试,但我不知道它是否适用于角度5,我认为应该可行. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
