Угловой 7 автообновление токен на предъявителя - PullRequest
0 голосов
/ 05 февраля 2019

У меня есть AuthService, по сути, с двумя методами: - getAuthToken (возвращает Promise, поэтому его можно лениво вызывать / вызывать несколько раз с блокирующим ожиданием для одного набора) - refreshToken (также возвращает Promise, использует доступный токен обновленияна исходном JWT, чтобы запросить новый токен аутентификации)

Я хотел бы автоматически

  • применить маркер переноса к каждому http-запросу (рабочий)
  • обновитьтокен при обновлении - и я почти у цели, за исключением того, что результат запроса с обновленным токеном не возвращает его исходному подписчику.

Вот код:

import { HttpEvent, HttpHandler, HttpHeaders, HttpInterceptor, HttpRequest } from "@angular/common/http";
import { from, Observable } from "rxjs";
import { Injectable } from "@angular/core";
import { AuthService } from "./auth.service";

@Injectable()
export class AuthHttpInterceptor implements HttpInterceptor {
  constructor(
    private _authService: AuthService,
  ) {
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return from(this.addBearerToken(req, next));
  }

  private async addBearerToken(req: HttpRequest<any>, next: HttpHandler): Promise<HttpEvent<any>> {
    const token = await this._authService.getAuthToken();

    const headerSettings = req.headers.keys().reduce(
      (acc, cur) => {
        acc[cur] = req.headers.getAll(cur);
        return acc;
      }, {});

    if (token) {
      headerSettings["Authorization"] = `Bearer ${ token }`;
    } else {
      console.log("performing request without auth!");
    }
    // prevent 302 redirect to challenge on a 401
    headerSettings["X-Requested-With"] = "XMLHttpRequest";
    const
      headers = new HttpHeaders(headerSettings),
      newRequest = req.clone({ headers });
    const result = next.handle(newRequest).toPromise();
    result.catch(async (err) => {
      if (err.status === 401) {
        const
          newToken = await this._authService.refreshToken();
        headerSettings["Authorization"] = `Bearer ${ newToken }`;
        const
          updatedHeaders = new HttpHeaders(headerSettings),
          updatedRequest = req.clone({ headers: updatedHeaders });
        console.log("requery with new token"); // <-- I see this when I have a 401, eg by altering the auth token to be bad, whilst leaving the refresh token alone
        return next.handle(updatedRequest).toPromise().then(data => {
          console.log("requeried data:", data); // <-- I also see this fire, with the valid data coming back from the second request
          return data; // <-- however the original caller doesn't get this data
        });
      }
    });
    return result;

  }
}

Я должен предположить, что это, вероятно, из-за моего смешивания Observables и Promises (что я делаю, потому что AuthService является асинхронным, используя Promises).Кроме того, если нет 401, исходный вызов проходит правильно - это как если бы цепочка обещаний просто сбрасывалась после строки

next.handle(newRequest).toPromise();

Чего мне не хватает?

1 Ответ

0 голосов
/ 08 февраля 2019

Здесь вы разрываете цепочку:

const result = next.handle(newRequest).toPromise();
result.catch(async (err) => {
  ...
});

return result;

result.catch возвращает новое обещание, и ваш обработчик не будет ждать всех действий, которые вы вызвали внутри catch.

Таким образом, вы можете написать это следующим образом:

const result = next.handle(newRequest).toPromise();
return result.catch(async (err) => {
  ...
});

Также то, что вы, вероятно, хотите сделать, это , не вызывайте refreshToken несколько раз, когда выполняется

cachedRequest: Promise<any>; // define prop in your class
...

if (!this.cachedRequest) {
  this.cachedRequest = this.authService.refreshToken();
}
const  newToken = await this.cachedRequest;
this.cachedRequest = null;

Вот Простая демоверсия , чтобы вы могли проверить это.( Я справляюсь с 404, но это не имеет значения )

...