Перехватчик Angular - как выйти из системы, если refre sh token interceptor не удается? - PullRequest
0 голосов
/ 19 февраля 2020

Информация

Я создаю перехватчик, чтобы использовать мой токен refre sh для обновления моего токена доступа, если я получу 401. Рабочий процесс выглядит следующим образом:

Отправляет запрос> получает 401> отправляет refre sh запрос> обновляет токен доступа> отправляет новый запрос

В настоящее время я работаю с обещаниями вместо наблюдаемых.


Вопрос

Как выйти из системы в случае сбоя последнего запроса?

Отправляет запрос> получает 401> отправляет refre sh запрос> обновления токен доступа> отправляет новый запрос> не удается> выйти из системы

У меня есть простой способ выхода из системы, но я не могу найти, где его разместить в перехватчике.


код

export class RefreshInterceptor implements HttpInterceptor {
    currentUser: User | null = null;
    private isRefreshing = false;
    private refreshTokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(
        null
    );

    constructor(private authenticationService: AuthenticationService) {
        this.authenticationService.currentUser.subscribe(
            user => (this.currentUser = user)
        );
    }

    intercept(
        request: HttpRequest<any>,
        next: HttpHandler
    ): Observable<HttpEvent<any>> {
        return next.handle(request).pipe(
            catchError(error => {
                // check if user is signed in
                if (!this.currentUser) {
                    return throwError(error);
                }

                // handle only 401 error
                if (error instanceof HttpErrorResponse && error.status === 401) {
                    return from(this.handle401Error(request, next));
                } else {
                    return throwError(error);
                }
            })
        );
    }

    /**
     * Adds the new access token as a bearer header to the request
     * @param request - the request
     * @param token - the new access token
     */
    private async addToken(request: HttpRequest<any>, token: string) {
        const currentUser = this.authenticationService.currentUserValue;

        if (currentUser && currentUser.accessToken) {
            return request.clone({
                setHeaders: {
                    Authorization: `Bearer ${token}`
                }
            });
        }

        return request;
    }

    private async handle401Error(request: HttpRequest<any>, next: HttpHandler) {
        // check if it is currently refreshing or not
        if (!this.isRefreshing) {
            this.isRefreshing = true;
            this.refreshTokenSubject.next(null);

            // send refresh request
            const token = await this.authenticationService.getRefresh();

            // update bearer token
            const newRequest = await this.addToken(request, token);

            // update values for next request
            this.isRefreshing = false;
            this.refreshTokenSubject.next(token);
            return next.handle(newRequest).toPromise();
        } else {
            const token = this.refreshTokenSubject.value();
            const newRequest = await this.addToken(request, token);
            return next.handle(newRequest).toPromise();
        }
    }
}

1 Ответ

0 голосов
/ 19 февраля 2020

Я решил это следующим образом:

  1. Изменен заголовок исходящего измененного запроса (добавлен заголовок повтора, чтобы я мог его идентифицировать позже).
  2. Создан новый перехватчик для выхода из системы
  3. Поиск запроса с заголовком повторной попытки. Подписал этот запрос.

Refre sh перехватчик токена

if (currentUser && currentUser.accessToken) {
            return request.clone({
                setHeaders: {
                    Authorization: `Bearer ${token}`,
                    Retry: "true"
                }
            });
        }

Перехватчик выхода из системы

@Injectable()
export class LogoutInterceptor implements HttpInterceptor {
    constructor(private authenticationService: AuthenticationService) {}

    intercept(
        request: HttpRequest<any>,
        next: HttpHandler
    ): Observable<HttpEvent<any>> {
        return next.handle(request).pipe(
            catchError(error => {
                // handle only 401 error
                if (error instanceof HttpErrorResponse && error.status === 401) {
                    from(this.handleRequest(request));
                    return throwError(error);
                }

                return next.handle(request);
            })
        );
    }

    private async handleRequest(request: HttpRequest<any>) {
        const isRetriedRequest = request.headers.get("retry");

        if (isRetriedRequest) {
            await this.authenticationService.logout();
        }
    }
}
...