Обновите токен перед отправкой клонированного запроса - PullRequest
2 голосов
/ 17 июня 2020

Итак, я хочу обновить токен доступа, если срок действия токена истек, используя токен refre sh, и так выглядит мой перехватчик токена:

intercept(req: HttpRequest<any>, next: HttpHandler) {
    let authservice = this.injector.get(AuthService)
      let tokenreq = req.clone({
        setHeaders: {
          Authorization: `Bearer ${authservice.setToken()}`
        }
      })
      return next.handle(tokenreq).pipe(
        catchError((error) => {
          if (error.error.message == 'The incoming token has expired') {
            authservice.renewToken()
            let tokenreq = req.clone({
              setHeaders: {
                Authorization: `Bearer ${authservice.setToken()}`
              }
            })
            return next.handle(tokenreq)
          }
          else return throwError(error)
        })
      );
    }
  }

Проблема возникает после того, как я получаю сообщение с истекшим токеном authservice.renewToken() и authservice.setToken() были вызваны одновременно, поэтому просроченный токен был установлен снова.

Другая проблема заключается в том, что пользователь снова открывает приложение с просроченным токеном в файлах cookie - все это метод GET выдаст ошибку и запросит новый токен несколько раз. Как я могу обработать ошибку токена истечения срока действия?

Ответы [ 2 ]

0 голосов
/ 26 июня 2020

вам необходимо передать новый токен.

return next.handle(request).pipe(
        map((event: HttpEvent<any>) => {
            return this.eventCallSendBack(event);
        }),
        catchError((error: HttpErrorResponse) => {
            if (error instanceof HttpErrorResponse) {
                switch (error.status) {
                    case 401:
                        return this.handle401Error(request, next);
                    case 403:
                        //DO Want you want here.
                        throw error;
                    default:
                        throw error;
                }
            }
            throw error;
        })
    );

Это функция обратного вызова.

private eventCallSendBack(event) {
    if (event instanceof HttpResponse) {
        return event.clone({ body: event.body });
    }
    return event;
}

Вы хотели бы иметь и добавить токен fn:

private addToken(event: HttpRequest<any>, token: string) {
    return event.clone({
        setHeaders: {
            Authorization: `Bearer ${token}`
        }
    });
}

А теперь предположим, что срок действия вашего токена истек, вам нужно создать fn, который получит новый токен из некоторой Auth.

private handle401Error(
    request: HttpRequest<any>,
    next: HttpHandler
): Observable<any> {
        return authServices
            .refreshToken(
                token //This is the old token to get the new.
            )
            .pipe(
                map(jwt => {
                    return jwt;
                }),
                switchMap((jwt: any) => {
                    return next
                        .handle(this.addToken(request, jwt.token)) // Add token in responce 
                        .pipe(
                            map((event: HttpEvent<any>) => {
                                return this.eventCallSendBack(event);
                            })
                        );
                }),
                catchError(err => {
                    return throwError(err);
                })
            );
    
}
0 голосов
/ 21 июня 2020

Вы можете исправить это поведение ошибки, подключив setToken к возвращаемому наблюдаемому с помощью оператора retryWhen. Таким образом, renewToken и setToken не будут выполняться параллельно И, что более важно, setToken будет приниматься во внимание цепочкой перехватчика в КАЖДОМ запросе.

intercept(req: HttpRequest<any>, next: HttpHandler) {
    const authservice = this.injector.get(AuthService);
      
    return of(req).pipe(
          switchMap((req) => {
            return authservice.setToken()               // Gets the token. *should rename this method to getToken()
                .pipe(
                    map(token => {                      // Set the token.
                        const tokenreq = req.clone({
                            setHeaders: {
                                Authorization: `Bearer ${authservice.setToken()}`
                            }
                            });

                        return tokenreq;
                    })
                ),
            switchMap(tokenreq => next.handle(tokenreq)), // Execute next interceptor and eventually send the request.
            retryWhen(errors => errors.pipe(
                mergeMap((err: HttpErrorResponse, i: number) => {
                    authservice.invalidateToken()        // Invalidate token. Erase token or expires it.
                    if (error.error.message == 'The incoming token has expired') {
                        return of(err);                   // will start the current pipe all over again - and get the token once again.
                    }

                    return throwError(error);
                })
            )
        )
  }

Пояснение:

В вопросе setToken не подключен к цепочке наблюдаемых, которые возвращаются методом перехватчиков. Последовательность выполнения кода до:

1) interceptor method execution -> setToken() -> return observable
2) request asked by http.get(..) -> chain of observables return by interceptors -> request sent -> chain of observables

И в этом ответе:

1) interceptor method execution -> setToken() -> return observable
2) request asked by http.get(..) -> chain of observables return by interceptors and setToken() inside one! -> request sent -> chain of observables

Примечание: метод

setToken должен возвращать наблюдаемый с токеном и invalidateToken должен иметь возможность удалить токен.

Это может быть легко достигнуто с помощью:

private token$: AsyncSubject<string>;

getToken(): Observable {
    if (!token$) this.token$ = new AsyncSubject();

    getTokenOperation.subscribe(t => {
        this.token$.next(t);
        this.token$.complete();
    })

    return this.token$.asObservable();
}

invalidateToken() {
    this.token$ = null;
}
...