• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Refresh token - guard zwraca przekierowanie przed wywołaniem interceptora (ANGULAR)

Object Storage Arubacloud
0 głosów
302 wizyt
pytanie zadane 19 marca 2022 w JavaScript przez rszczepanski02 Obywatel (1,180 p.)
edycja 19 marca 2022 przez ScriptyChris

Cześć. Mam mały problem dot. autoryzacji. W momencie wygaśnięcia tokenu, które zostanie wykryte podczas przejścia na inną podstronę zwracany jest błąd 401 (prawidłowo) i dopiero po zakończeniu akcji guard'a wykonywany jest interceptor, który zwróci nowy access token. Problem w tym, że chciałbym aby ten interceptor wykonał się w trakcie trwania guarda, aby guard zaczekał na odpowiedź, którą on zwróci.

 

Interceptor:

return next.handle(clonedReq)
        .pipe(
          catchError((err: HttpErrorResponse) => {
            if (err.error.code === 'EXPIRED') {
                  return this.handle401Error(clonedReq, next);
            } else if (err.error.status === 401) {
                  this.router.navigateByUrl('/login');
                  return throwError(err.error.message);
            }

            // Redirect to an error landing page
            return throwError(err.error.message);
          })
        );

private handle401Error(request: HttpRequest<any>, next: HttpHandler) {

    if (!this.isRefreshing) {
      this.isRefreshing = true;
      this.refreshTokenSubject.next(null);

      return this.authService.refreshToken()
        .pipe(
          switchMap((token: any) => {
          this.refreshTokenSubject.next(token.new_access_token);
          this.authService.setToken(token.new_access_token);

          return next.handle(this.addToken(request, token.new_access_token));
        }), catchError(err => { 

          // .subscribe() not needed!Just an error handler
          if (err.error.code === 'EXPIRED') {
                this.authService.deleteToken();
                this.router.navigateByUrl('/login');
                return throwError(err.error.message);
          }
          
          // Redirect to error landing page
          return throwError(err.error.message);
      }),
      finalize(() => {
        this.isRefreshing = false;
      })
    );

Guard:

import { ToastMessageService } from './../shared/reusable-components/toast-message/toast-message.service';
import { IAuthorizatedUser } from './../shared/interfaces/AuthorizatedUser';
import { AuthService } from './../shared/services/auth.service';
import { CanActivate, Router } from "@angular/router";
import { catchError, map, Observable, of } from 'rxjs';
import { AccountType } from '../shared/constants/account-type';
import { Injectable } from '@angular/core';
import { toastMessageType } from '../shared/constants/toastMessageType';

@Injectable({ providedIn: 'root' })
export class AuthGuard implements CanActivate {
  constructor(
    private authService: AuthService,
    private router: Router,
    private readonly toastMessageService: ToastMessageService
  ) {}

  canActivate(): Observable<boolean> {
    return this.userHasAccess();
  }

  userDataSetup(user: IAuthorizatedUser): void {
    this.authService.setAuthorizatedUser(user);
  }

  userHasAccess(): Observable<boolean> {
    return this.authService.getUserFromToken().pipe(
      map(response => {
        // this.redirectToLastRoute();
        if(response.body.accountType === AccountType.CREATOR) {
          this.userDataSetup(response.body);
          return true;
        }
        this.toastMessageService.setMessage(
          'Authentication',
          'Sorry, you are not allowed to go there',
          toastMessageType.ERROR,
          5
        );
        this.router.navigate(['/']);
        return false;
      }),
      catchError(() => {
        this.toastMessageService.setMessage(
          'Authentication',
          'Sorry, you are not allowed to go there',
          toastMessageType.ERROR,
          5
        );
        this.router.navigate(['/']);
        return of(false);
      })
    )
  }

  // redirectToLastRoute(): void {
  //   const redirect = localStorage.getItem('redirectTo');
  //   if(redirect) {
  //     this.router.navigate([redirect]);
  //     localStorage.removeItem('redirectTo');
  //   }
  // }

}

 

 

Z góry bardzo dziękuję za pomoc!

1 odpowiedź

0 głosów
odpowiedź 19 marca 2022 przez Wiciorny Ekspert (270,110 p.)
return next.handle(clonedReq)
        .pipe(
          catchError((err: HttpErrorResponse) => {
            if (err.error.code === 'EXPIRED') {
                  return this.handle401Error(clonedReq, next);
            } else if (err.error.status === 401) {
                  this.router.navigateByUrl('/login');
                  return throwError(err.error.message);
            }
 
            // Redirect to an error landing page
            return throwError(err.error.message);
          })
        );

może zamiast od razu subskrybować w momencie zwracania wartości ( otrzymania obserwable) ... po prostu zrób obserwatora jako interceptor" z oczekiwaniem na rezultat, a subskrybcie wykonaj w  guardzie w momencie kiedy chcesz i dopiero po zwróceniu rezultatu z interceptora kontynułuj działanie ? 

Idea tego byłaby podobna do tego co ma miejsce z wykorzystanie Promis-await.  gdzie tak naprawdę wykonania asynchroniczne zwracają Ci obietnice "od czegoś" np zapytania http i rezultatu, a " przetworzenie wyniku"  wykonujesz przez wybrany siebie punkt przerwania. 
Idea moja jest taka, żeby wymagany parametr "interceptora" przekazać w guardzie. 

Jedna sprawa się pojawiła, skoro guard zwraca odp. wygaszenia tokena np, to nie jest to dobre rozwiązanie aby jednocześnie przed jego zakończeniem ustawiać token, bo w takim razie komunikat jest błędny. 

Podobne pytania

+1 głos
1 odpowiedź 190 wizyt
pytanie zadane 12 listopada 2020 w JavaScript przez LixI Nowicjusz (130 p.)
0 głosów
1 odpowiedź 366 wizyt
pytanie zadane 20 maja 2020 w JavaScript przez mi-20 Stary wyjadacz (13,190 p.)
0 głosów
1 odpowiedź 350 wizyt
pytanie zadane 21 października 2018 w JavaScript przez mi-20 Stary wyjadacz (13,190 p.)

92,570 zapytań

141,422 odpowiedzi

319,643 komentarzy

61,958 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...