Угловой: Добавление токена на предъявителя в перехватчик

#angular #angular-http-interceptors

Вопрос:

Я работаю с Angular AWS Cognito

Я смог войти в систему и мне нужно добавить токен на предъявителя cognito

 @Injectable({
providedIn: 'root',
})
export class InterceptorService implements HttpInterceptor {
constructor(public loaderService: LoaderService, private router: Router) { }

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return this.getToken().pipe(
        mergeMap((token) => {
            request = request.clone(
                {
                    setHeaders: { Authorization: `Bearer ${token}` }
                });

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

getToken() {
    return from(
        new Promise((resolve, reject) => {
            Auth.currentSession().then((session) => {
                if (!session.isValid()) {
                    resolve(null);
                } else {
                    resolve(session.getIdToken().getJwtToken());
                }
            }).catch(err => { return resolve(null) });
        })
    );
}
}
 

Этот код работает нормально, проблема в том, как обработать HttpResponse здесь?

Я попытался следовать коду, но это не сработало, у запроса нет токена на предъявителя

 intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        return next.handle(request).pipe(
            tap(
            (event) => {
                if (event instanceof HttpResponse) {
                    if (event.status !== 200) {
                        console.log('Response', event.status);
                    }
                } else {
                    return this.getToken().pipe(
                       mergeMap((token) => {
                            request = request.clone(
                                {
                                    setHeaders: { Authorization: `Bearer ${token}` }
                                });

                            return next.handle(request);
                        })
                    );
                }
            },
            (error) => {
                 // to handle errors
            }
        )
}
 

Комментарии:

1. Пожалуйста, проверьте ссылку на демонстрационную ссылку stackblitz. Надеюсь, это вам поможет.

Ответ №1:

Насколько я знаю tap , запускается только тогда, когда ошибки нет. Если вы хотите, чтобы ваша функция выполнялась при ошибке, которую вы должны использовать catchError() в канале.

Ответ №2:

tap — это оператор для создания побочных эффектов, вы не можете просто вернуть наблюдаемое из обратного вызова, на него не будет подписана подписка. также немного странна логика, в которой вы отправляете исходный запрос и повторяете его с помощью токена, если он завершается неудачно. Я считаю, что вы должны добавлять токен к каждому запросу.

 intercept(...) {
  return this.sendWithToken(request).pipe(
    catchError(error => error.status === 401 ? this.sendWithToken(request) : throwError(error)) // try one more time if return code is 401 
  );
}

sendWithToken(request: ...) {
  return this.getToken().pipe(
    mergeMap(token => addToken(request)),
    mergeMap(authedRequest => next.handle(authedRequest)),
  );
}
 

также код getToken может быть улучшен, потому что вам не нужно создавать обещание, если оно у вас уже есть

 getToken() {
    return from(
        Auth.currentSession().then((session) => {
            if (!session.isValid()) {
                return null;
            } else {
                return session.getIdToken().getJwtToken();
            }
        }).catch(err => null);
    );
}
 

Ответ №3:

Я решил эту проблему с помощью следующего кода перехватчика:

 intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return this.getToken().pipe(
        mergeMap((token) => {
            request = request.clone(
                {
                    headers: request.headers.set('Authorization', `Bearer ${token}`)
                });

            return next.handle(request).pipe(
                tap(evt => {
                      // modify here
                }),
                catchError((error: any) => {
                    if (error amp;amp; error.status) {
                        if (error.status == 401) {
                            this.router.navigate(['/']);
                        }
                    } else {
                        return throwError(error);
                    }
                })
            )
        })
    );
}

getToken() {
    return from(
        Auth.currentSession().then((session) => {
            if (!session.isValid()) {
                return null;
            } else {
                return session.getIdToken().getJwtToken();
            }
        }).catch(err => null)
    );
}