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,我认为应该可行. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |