Angular 5 Http Interceptor обновляет токен JWT

Я уже реализовал логику сохранения и извлечения токенов, а также обновляю вызов. Проблема в том, что когда я перехватываю 403 в своем HttpInterceptor, другие вызовы, которые выполняются в то же время, также обновляют токен. Я хотел бы удерживать эти звонки, пока мой токен не будет обновлен. Чтобы создать то, что я бы назвал «семафором» запросов.

@Injectable()
export class TokenInterceptor implements HttpInterceptor {

private auth: AuthService;

constructor(private injector: Injector) {
}

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    this.auth = this.injector.get(AuthService);

    if(this.auth.isAuthenticated()){
        request = request.clone({
            setHeaders: {
                Accept: 'application/json',
                Authorization: `Bearer ${localStorage.getItem('access_token')}`
            }
        });
    } else {
        request = request.clone({
            setHeaders: {
                Accept: 'application/json'
            }
        });
    }

    return next.handle(request).catch(error => {
        if (error.status === 401) {
            console.log('refreshing token');

            // TODO: return Refresh Token here and hold other calls
        }

        return Observable.throw(error);
    });
}

person Bartando    schedule 02.01.2018    source источник
comment
Не могли бы вы опубликовать свой код HttpInterceptor?   -  person Dmitry    schedule 02.01.2018
comment
Хорошо, я обновил свой вопрос. Не знаю, почему все минусы.   -  person Bartando    schedule 03.01.2018
comment
Вы уверены, что обновление токена после получения 401 — это хорошая идея? Этой проблемы не было бы, если бы вы использовали время истечения срока действия токена JWT, чтобы определить, когда обновлять до истечения срока его действия.   -  person Vojtech    schedule 18.01.2018
comment
Я думаю, что для большей безопасности срок действия токена должен истекать через некоторое время.   -  person Bartando    schedule 18.01.2018
comment
Да, он истекает через некоторое время, но информация об этом должна быть закодирована в токене и, следовательно, проанализирована и использована во внешнем интерфейсе для своевременного обновления токена.   -  person Vojtech    schedule 23.01.2018
comment
@Bartando, не могли бы вы сообщить нам, сработало ли приведенное ниже решение?   -  person G_S    schedule 12.09.2018


Ответы (1)


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

Ваш перехватчик должен быть примерно таким:

@Injectable()
export class TokenInterceptor implements HttpInterceptor {

  private auth: AuthService;

  constructor(private injector: Injector) {
    this.auth = this.injector.get(AuthService);
  }

  setHeaders(request) {
    return function (token) {
      return request.clone({
        setHeaders: {
          Accept: 'application/json',
          Authorization: `Bearer ${token}`
        }
      });
    }
  }

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return this.auth
      .getToken()
      .map(this.setHeaders(request))
      .mergeMap(next.handle)
      .catch(error => {
        if (error.status === 401) {
          return this.auth.refreshToken()
            .map(this.setHeaders(request))
            .mergeMap(next.handle);
        }
        return Observable.throw(error);
      });
  }

}

И ваш AuthService:

@Injectable()
export class AuthService {

  private refreshTokenCall;

  saveTokenInLocalStorage(token) {
    localStorage.setItem('access_token', token);
  }

  getToken() {
    if (localStorage.getItem('access_token')) {
      return Observable.of(localStorage.getItem('access_token'));
    }

    return this.refreshToken();
  }

  refreshToken() {
    if (!this.refreshTokenCall) {
      this.refreshTokenCall = this.http.get(refreshTokenURL)
        // Maybe a .map() here, it depends how the backend returns the token
        .do(this.saveTokenInLocalStorage)
        .finally(() => this.refreshTokenCall = null);
    }
    return this.refreshTokenCall;
  }

}

Я надеюсь, что это поможет вам как-то.

person Leandro Lima    schedule 22.01.2018
comment
Я попробую это, и если это сработает, награда за вас :) Спасибо - person Bartando; 23.01.2018
comment
Объяснение сделало бы этот ответ еще лучше, пожалуйста, добавьте его, если хотите. Как эти вызовы ожидают обновления токена? - person Gabriel Luca; 03.02.2020