У меня есть 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();
Чего мне не хватает?