簡體   English   中英

Angular HTTP Interceptor 等待 http 請求,直到獲得刷新令牌

[英]Angular HTTP Interceptor wait http requests until get a refresh token

我已經構建了我的 AuthInterceptor,它在 401 錯誤時發送請求以獲取新令牌。

當我遇到 401 錯誤時會調用 handle401Error 方法,但我正在嘗試等待其他 HTTP 請求,直到我獲得新令牌。 但是它不會等到獲得新的刷新令牌,盡管它正在對一個新的訪問令牌進行 HTTP 調用。 請找到我附上的截圖。

在此處輸入圖片說明

攔截器

isRefreshingToken = false;
tokenSubject: BehaviorSubject<string | null> = new BehaviorSubject<string | null>(null);

intercept(
    request: HttpRequest<any>,
    next: HttpHandler
): Observable<HttpEvent<any>> {

    const timeOut = appSettings.ajaxTimeout;
    const retryCount = appSettings.retryCount;
    const retryDelay = appSettings.retryDelayMS;

    return next.handle(request).pipe(
        timeout(timeOut),
        catchError((error) => {
            if (error instanceof HttpErrorResponse) {
                const httpErrorCode: number = error['status'];
                switch (httpErrorCode) {
                    case StatusCodes.BAD_REQUEST:
                        return throwError(error);
                        //return this.handle400Error(error);
                    case StatusCodes.UNAUTHORIZED:
                        return this.handle401Error(request, next);
                    default:
                        this._toastr.error(
                            'Sorry! something went wrong.',
                            'Error!'
                        );
                        return throwError(error);
                }
            } else {
                return throwError(error);
            }
            }),
            retryWhen((errors) => {
                return errors.pipe(
                    concatMap((error, count) => {
                        if (count < retryCount) {
                            return of(error);
                        }
                        return throwError(error);
                    }),
                    delay(retryDelay)
                );
            })
        );
    }

    handle401Error(
        request: HttpRequest<any>,
        next: HttpHandler
    ): Observable<HttpEvent<any>> {
        if (!this.isRefreshingToken) {
            this.isRefreshingToken = true;
            console.log('401');

            // Reset here so that the following requests wait until the token
            // comes back from the refreshToken call.
            this.tokenSubject.next(null);

            return this._spotify.getRefreshToken().pipe(
                switchMap((authData: ISpotifyTokens) => {
                    if (authData) {
                        console.log('new token success');
                        this.updateTokenInCookie(authData);
                        this.tokenSubject.next(authData.access_token);
                        return next.handle(request);
                    }
                    return this.logoutUser();
                }),
                catchError((error) => {
                    // If there is an exception calling 'refreshToken', bad news so logout.
                    return this.logoutUser();
                }),
                finalize(() => {
                    this.isRefreshingToken = false;
                })
            );
        } else {
            return next.handle(request);
        }
    }

    updateTokenInCookie(authData: ISpotifyTokens) {
        this._spotify.updateTokensInStorage(authData);
        this._spotify.startRefreshTokenTimer(authData.expires_in);
    }

    logoutUser() {
        this._spotify.clearTokensFromStorage();
        this._router.navigate(['/welcome']);
        return throwError('');
    }

我已經使用下面的代碼解決了這個問題。 如果有人有任何黃油解決方案,請提出建議。

private isRefreshingToken = false;
private timeOut = appSettings.ajaxTimeout;
private tokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);

intercept(
    request: HttpRequest<any>,
    next: HttpHandler
): Observable<HttpEvent<any>> {
    return next.handle(request).pipe(
    timeout(this.timeOut),
    catchError((error) => {
        if (error instanceof HttpErrorResponse) {
        const httpErrorCode: number = error['status'];
        switch (httpErrorCode) {
            case StatusCodes.BAD_REQUEST:
              return throwError(error);
            case StatusCodes.UNAUTHORIZED:
              return this.handle401Error(request, next);
            default:
              this._toastr.error(
                'Sorry! something went wrong.',
                'Error!'
              );
              return throwError(error);
           }
           } else {
             return throwError(error);
           }
       })
    );
}

private handle401Error(
    request: HttpRequest<any>,
    next: HttpHandler
): Observable<HttpEvent<any>> {
        if (!this.isRefreshingToken) {
            this.isRefreshingToken = true;
            // Reset here so that the following requests wait until the token
            // comes back from the refreshToken call.
            this.tokenSubject.next(null);
            return this._spotify.getRefreshToken().pipe(
                switchMap((response: ISpotifyTokens) => {
                    console.log('updating on 401');
                    // Updating new token in cookie
                    this._spotify.updateTokensInStorage(response, false);
                    this.tokenSubject.next(response.access_token);
                    return next.handle(
                        this.addTokenInHeader(request, response.access_token)
                    );
                }),
                catchError((error) => {
                    // If there is an exception calling 'refreshToken', bad news so logout.
                    this.logoutUser();
                    return throwError('');
                }),
                finalize(() => {
                    this.isRefreshingToken = false;
                })
            );
        } else {
            return this.tokenSubject.pipe(
                filter((token) => token != null),
                take(1),
                switchMap((token) => {
                    return next.handle(this.addTokenInHeader(request, token));
                })
            );
        }
    }

addTokenInHeader(
    request: HttpRequest<any>,
    token: string
): HttpRequest<any> {
    return request.clone({
        setHeaders: { Authorization: 'Bearer ' + token }
    });
}

logoutUser(): void {
    this._spotify.clearTokensFromStorage();
    this._router.navigate(['/welcome']);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM