簡體   English   中英

Angular 12 HttpInterceptor 等待 http 客戶端方法完成

[英]Angular 12 HttpInterceptor Wait until a http client method finish

嗨,我正在嘗試檢查令牌何時到期並使用訪問令牌重新加載它。 主要問題是要重新加載它,我必須進行 http 調用以獲取新令牌,然后將其重新保存在會話存儲中。 主要問題是,因為 http 是異步的,它會重新加載令牌,但是因為我不知道如何等到此調用完成以使用新令牌重試原始調用,所以它失敗了。

這是代碼:

AuthService:這是被調用以更新令牌的服務

async reloadIdTokenFromAccess(accessToken : string | null) {
  console.log("Performing call to reload token");
  const resp = await this.httpClient.post<IdTokenDTO>(`${environment.backendUrl}/auth/tokenReload`,accessToken).toPromise();
  this.setIdToken(resp.idToken);
  this.setExpireAt(resp.expireAt);
  console.log("Data update in session storage")
}

攔截器

@Injectable()
export class HttpTokenInterceptor implements HttpInterceptor {

  constructor(private authServ : AuthService) {}

  intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {

    let token: string | null = this.authServ.getIdToken();
    let expiration: number | null = this.authServ.getExpireAt();
    let reloaded : boolean = false;

    var currentTime = new Date().getTime();

    if(expiration != null && !request.url.includes("tokenReload") && !request.url.includes("login")){
      if(expiration <= currentTime + 60000 && this.authServ.getAccessToken() != null){
        reloaded = true;
        console.log("Token expiration Time near to expire, reloading token")
        this.authServ.reloadIdTokenFromAccess(this.authServ.getAccessToken());
        token = this.authServ.getIdToken();
        console.log("Finish all full reloading")
      }
    }

    if(reloaded){
      console.log("Starting the request with the new token")
    }

    let originalReq = request;

    if(token){
      request = originalReq.clone({
        setHeaders: {
          authorization: `Bearer ${ token }`,
          'Content-Type': 'application/json'
        }
      });
    }

    return next.handle(request);
  }
}

如果我檢查日志,我會看到以下內容: 在此處輸入圖片說明

正如您可以在重新加載令牌之前檢查請求是否正在執行。 在繼續使用該方法之前,如何強制完成此請求?

就像在 java CompletableFuture 中一樣,使用 get() 方法阻止代碼直到它完成

我也有這樣的測試沒有成功

async reloadIdTokenFromAccess(accessToken : string | null) {
  console.log("Performing call to reload token");
  await this.httpClient.post<IdTokenDTO>(`${environment.backendUrl}/auth/tokenReload`,accessToken).subscribe( (resp : IdTokenDTO) => {
    this.setIdToken(resp.idToken);
    this.setExpireAt(resp.expireAt);
    console.log("updates token in session storage")
  })
}
import { Injectable } from '@angular/core';
import {HttpRequest,HttpHandler,HttpEvent,HttpInterceptor} from '@angular/common/http';
import { from, Observable, Subscription } from 'rxjs';
import { AuthService } from '../services/auth.service';

@Injectable()
export class HttpTokenInterceptor implements HttpInterceptor {

  constructor(private authServ : AuthService) {}

  intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
    return from(this.handle(request, next));
  }

  async handle(request: HttpRequest<any>, next: HttpHandler) {

    const expiration: number | null = this.authServ.getExpireAt();
    const currentTime = new Date().getTime();
    let reloaded: boolean = false;

    if (expiration != null && !request.url.includes('tokenReload') &&!request.url.includes('login')) {
      if (expiration <= currentTime + 60000 && this.authServ.getAccessToken() != null) {
        reloaded = true;
        console.log('Token expiration Time near to expire, reloading token');
        await this.authServ.reloadIdTokenFromAccess(this.authServ.getAccessToken());
        console.log('Finish of call reaload token');
      }
    }

    const token = this.authServ.getIdToken();

    if (reloaded){ 
      console.log('Starting the request with the new token');
    }

    const originalReq = request;

    if (token) {
      request = originalReq.clone({
        setHeaders: {
          authorization: `Bearer ${token}`,
          'Content-Type': 'application/json',
        },
      });
    }
    return next.handle(request).toPromise();

  }
}

我很絕望。 不知道該怎么做(也許繼續學習課程和教程,但我有 dedlines):(

提前致謝。

在您的authService ,使用Observables返回 http 響應

reloadIdTokenFromAccess(accessToken : string | null): Observable<IdTokenDTO> {
    console.log("Performing call to reload token");
    return this.httpClient.post<IdTokenDTO>(`${environment.backendUrl}/auth/tokenReload`,accessToken);
}

而且,在你的攔截器中,你會像這樣繼續:

intercept(
    request: HttpRequest<unknown>,
    next: HttpHandler
  ): Observable<HttpEvent<unknown>> {
    const expiration: number | null = this.authServ.getExpireAt();
    const currentTime = new Date().getTime();
    let reloaded: boolean = false;

    if (
      expiration != null &&
      !request.url.includes('tokenReload') &&
      !request.url.includes('login')
    ) {
      if (
        expiration <= currentTime + 60000 &&
        this.authServ.getAccessToken() != null
      ) {
        reloaded = true;
        console.log('Token expiration Time near to expire, reloading token');

        // unwrap your response from the observable
        this.authServ
          .reloadIdTokenFromAccess(this.authServ.getAccessToken())
          .pipe(
            tap((response: any) => {
              this.authServ.setIdToken(response.idToken);
              this.authServ.setExpireAt(response.expireAt);
              console.log('Data update in session storage');
            })
          )
          .subscribe(() => this.addToken(request, reloaded));
      }
    }

    const req = this.addToken(request, reloaded);
    return next.handle(req);
  }

  private addToken(request: HttpRequest<unknown>, reloaded: boolean) {
    const token = this.authServ.getIdToken();
    console.log('Finish all full reloading');

    if (reloaded) console.log('Starting the request with the new token');

    const originalReq = request;

    if (token) {
      request = originalReq.clone({
        setHeaders: {
          authorization: `Bearer ${token}`,
          'Content-Type': 'application/json',
        },
      });
    }

    return request;
  }

您應該使用更高階的 observable。 這是一個不錯的閱讀https://blogs.msmvps.com/deborahk/higher-order-observable/

嘗試執行以下操作:

reloadIdTokenFromAccess(accessToken : string | null) : Observable<IdTokenDTO> {
    console.log("Performing call to reload token");
    return this.httpClient.post<IdTokenDTO>(`${environment.backendUrl}/auth/tokenReload`,accessToken)
      .tap( (resp : IdTokenDTO) => {
        this.setIdToken(resp.idToken);
        this.setExpireAt(resp.expireAt);
        console.log("updates token in session storage")
      });
  }

每次重新加載時, tap都會攔截並保存令牌,它會返回可觀察對象,然后可以將其與另一個可觀察對象組合。

@Injectable()
export class HttpTokenInterceptor implements HttpInterceptor {

  constructor(private authServ : AuthService) {}

intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
    const expiration: number | null = this.authServ.getExpireAt();
    const currentTime = new Date().getTime();
    let reloaded: boolean = false;

    if (expiration != null && !request.url.includes('tokenReload') &&!request.url.includes('login')) {
      if (expiration <= currentTime + 60000 && this.authServ.getAccessToken() != null) {

        console.log('Token expiration Time near to expire, reloading token');

        return this.reloadIdTokenFromAccess(this.authServ.getAccessToken()).pipe(
          concatMap(token => {
            request = request.clone({
              setHeaders: {
                authorization: `Bearer ${token}`,
                'Content-Type': 'application/json',
              }
            });
            return next.handle(request);
          })
        )

        console.log('Finish of call reaload token');
      }
    }
    
    return next.handle(request);
  }
}


  

concatMap將等待先前的 HTTP Observable 完成,然后再將新值映射到 HTTP Observable

我終於使用了一個計時器,每 X 分鍾檢查一次令牌。 靜默重裝。 我把這個計時器放在應用程序的主要組件中,就是這樣。

不管怎么說,還是要謝謝你。


export class MainComponent implements OnInit, OnDestroy{
...
public subscription : Subscription;
  ngOnInit(): void {
    this.subscription = timer(0, (300 *1000)).pipe().subscribe(() => {
      //console.log("ejecutando recarga del token");
      const expiration: number | null = this.authServ.getExpireAt();
      const currentTime = new Date().getTime();

      let reloaded: boolean = false;

      if (expiration != null) {
        if (expiration <= currentTime + (350 * 1000) && this.authServ.getAccessToken() != null) {
          reloaded = true;
          //console.log('Token expiration Time near to expire, reloading token');
          this.authServ.reloadIdTokenFromAccess(this.authServ.getAccessToken());
        }
      }
    });
  }
  ngOnDestroy() {
    this.subscription.unsubscribe();
  }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM