• 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)

Aruba Cloud PRO i VPS, Openstack, VMWare, MS Hyper-V
0 głosów
104 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 (251,470 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ź 99 wizyt
pytanie zadane 12 listopada 2020 w JavaScript przez LixI Nowicjusz (130 p.)
0 głosów
1 odpowiedź 177 wizyt
pytanie zadane 20 maja 2020 w JavaScript przez mi-20 Stary wyjadacz (13,140 p.)
0 głosów
1 odpowiedź 314 wizyt
pytanie zadane 21 października 2018 w JavaScript przez mi-20 Stary wyjadacz (13,140 p.)

90,828 zapytań

139,504 odpowiedzi

313,594 komentarzy

60,325 pasjonatów

Motyw:

Akcja Pajacyk

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

Sklep oferujący ćwiczenia JavaScript, PHP, rozmowy rekrutacyjne dla programistów i inne materiały

Oto dwie polecane książki warte uwagi. Pełną listę znajdziesz tutaj.

...