加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

Angular 5 HttpClient拦截器JWT刷新令牌无法捕获401并重试我的请

发布时间:2020-12-17 10:24:57 所属栏目:安全 来源:网络整理
导读:我正在尝试实现401响应的捕获并尝试获取基于 Angular 4 Interceptor retry requests after token refresh的刷新令牌.我试图实现相同的事情,但我从来没有能够重试该请求,我真的不确定这是否是最好的应用刷新令牌策略的方法. 这是我的代码: @Injectable()expo
我正在尝试实现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);
  }
}

I noticed that It was better if I have two Interceptors one to refresh the token and handle that and one to put the Authorization Header if exist.

这是用于刷新令牌的拦截器:

@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,我认为应该可行.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读