Http-вызов внутри Angular Guard для проверки JWT

#angular #jwt #angular-router-guards

Вопрос:

Хорошая ли идея вызвать сервер в guard, чтобы проверить, действителен ли jwt?

Я храню jwt на интерфейсе, но я не знаю, истек ли срок действия этого токена или он внесен в черный список, если я не свяжусь с серверной частью. Кроме того, я не знаю роли пользователя, что важно для меня для AdminGuard.

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

После некоторых поисков я нашел библиотеку для angular, чтобы проверить jwt. А что касается ролей, я мог бы просто сохранить роль пользователя в качестве полезной нагрузки, а затем декодировать ее с помощью этой библиотеки jwt. Маркеры, занесенные в черный список, могут быть проблемой, но я думаю, что это редкий сценарий, и даже если охранник позволит этому пользователю продолжить движение по определенному маршруту, мой сервер просто вернет ошибку при первом запросе, и я перенаправлю.

Должен ли я попробовать второй подход? Или http-вызовы не имеют большого значения для охранников?

Ответ №1:

Теперь вот в чем дело, если вы хотите следовать рекомендациям, я бы рекомендовал использовать an interceptor для проверки 401 несанкционированных ошибок (в основном это происходит, когда срок действия токенов истек). и в этом interceptor случае вы можете вызвать login метод из своей auth службы, чтобы обновить свой токен и повторить запрос.

Вот пример кода:

 import { Injectable } from '@angular/core';
import {
  HttpRequest,
  HttpHandler,
  HttpInterceptor,
  HttpErrorResponse,
} from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError, retry } from 'rxjs/operators';
import { Router } from '@angular/router';
import { StorageService } from 'src/app/services/storage.service';
import { AuthService } from 'src/app/modules/auth/auth.service';
import { User } from 'src/app/models/entities/user.interface';
import { ToastService } from 'src/app/services/toast.service';
import { NgxSpinnerService } from 'ngx-spinner';
@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
  constructor(
    private _authService: AuthService,
    private _storageService: StorageService,
  ) {}
  //!Global scope error handling
  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<any> {
    return next.handle(request).pipe(
      // -> retry(1),
      catchError((error: HttpErrorResponse) => {
        if (error.error instanceof ErrorEvent) {
          // handle client-side error
        } else {
          // handle server-side error
          //-> i.e. 401, 404, 500, etc..
          //-> Also refresh token for expired token
          switch (error.status) {
            case 401: //login
              this._authService
                .postLogin(this._storageService.getLocalObject('credentials'))
                .subscribe((user: User) => {
                  this._storageService.setLocalObject('user', user);
                  this._storageService.setToken(user.jwtToken);
                });
              break;
            case 403: //forbidden
              break;
            case 404: //not found
              break;
            case 500: //internal server error
              break;
          }
        }
        return throwError(error);
      })
    );
  }
}
 

Держите все отдельно, чтобы увеличить возможность повторного использования. Так что это » нет » для вызова HTTP запроса в вашем Guard .