繁体   English   中英

Angular 等待方法完成

[英]Angular wait for method to finish

我有 HTTP 拦截器拦截 http 请求 api

首先它检查这个 api 是否需要授权,然后检查 session 变量以查看是否已经保存了令牌并检查它是否有效

如果没有令牌或令牌已过期,则应获取新令牌,然后照常进行

代码 rest 在检索令牌之前执行,然后它不添加所需的身份验证 header。我不知道如何让它等待。

intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
    let authReq = request;
    const token = this.checkUrl(authReq.url)
    if (token){
      authReq = request.clone({ 
        headers: request.headers.set(this.TOKEN_HEADER_KEY, 'Bearer ' + token) 
      });
    }
    return next.handle(authReq);
  }

获取令牌并检查是否需要身份验证的checkUrl方法

checkUrl(url: string): string {
    if (url.includes('/login')){
      return ''
    }
    for (let x of this.includedList) {
      if (url.includes(x.url)){
        return this.auth.getApiToken()
        //break;
      }
    }
    return ''
  }

从 session 存储或登录端点获取令牌的getApiToken方法

getApiToken(): string{
    let token = <string>sessionStorage.getItem('auth-token');
    if (!token || this.jwt.isTokenExpired(token)){
      this.apiLogin().subscribe({
        next: data => {
          console.log(data)
          sessionStorage.setItem("auth-token", data.token)
          token = data.token
        },
        error: err => {
          console.log(err)
          token = ''
        }
      })
    } 
    return token;
  }

最后是从 api 获取新令牌的apiLogin方法

apiLogin(): Observable<any> {
    const loginData = {
      username: environment.apiLoginData.username,
      password: environment.apiLoginData.password
    }
    return this.http.post(AUTH_API, loginData);
  }

编辑

我尝试使用 Observable 和 map 的解决方案

interceptor

intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
    let authReq = request;
    let token = ''
    this.checkUrlV2(authReq.url).pipe(map(data => {
      console.log(data)
      token = data
    }));
    console.log('token')
    console.log(token)
    if (token){
      authReq = request.clone({ 
        headers: request.headers.set(this.TOKEN_HEADER_KEY, 'Bearer ' + token) 
      });
    }
    return next.handle(authReq);
  }

checkUrlV2

checkUrlV2(url: string): Observable<string> {
    if (url.includes('/login')){
      return of('')
    }
    for (let x of this.includedList) {
      if (url.includes(x.url)){
        this.auth.apiTokenV2().pipe(map(data => {
          console.log(data)
          return of(data)
        }));
        //break;
      }
    }
    return of('')
  }

apiTokenV2

apiTokenV2() {
    let token = ''
    if (!token || this.jwt.isTokenExpired(token)){
      this.apiLogin().pipe(map(data => {
        console.log(data)
        sessionStorage.setItem("auth-token", data.token)
        return of(data.token)
      }));
    }
    return of(token)
  }

找到适合我的案例的解决方案。 它确实在不检查令牌的情况下请求,如果出现错误则刷新它

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    req = this.addAuthenticationToken(req);

    return <Observable<HttpEvent<any>>>next.handle(req).pipe(
      catchError((error: HttpErrorResponse) => {
        if (error && error.status === 401) {
          if (this.refreshTokenInProgress) {
            // If refreshTokenInProgress is true, we will wait until refreshTokenSubject has a non-null value which means the new token is ready and we can retry the request again
            return this.refreshTokenSubject.pipe(
              filter(result => result !== null),
              take(1),
              switchMap(() => next.handle(this.addAuthenticationToken(req)))
            );
          } else {
            this.refreshTokenInProgress = true;
            // Set the refreshTokenSubject to null so that subsequent API calls will wait until the new token has been retrieved
            this.refreshTokenSubject.next(null);
            
            return this.refreshAccessToken().pipe(
              switchMap((success: boolean) => {               
                this.refreshTokenSubject.next(success);
                return next.handle(this.addAuthenticationToken(req));
              }),
              // When the call to refreshToken completes we reset the refreshTokenInProgress to false for the next time the token needs to be refreshed
              finalize(() => this.refreshTokenInProgress = false)
            );
          }
        } else {
          return throwError(() => new Error(error.message));
        }
      })
    );
  }

  private refreshAccessToken(): Observable<any> {
    return this.auth.apiLogin().pipe(map(authData => {
      console.log('Token refreshed')
      sessionStorage.setItem("auth-token", authData.token)
      return authData.token
    }))
  }
  private addAuthenticationToken(request: HttpRequest<any>): HttpRequest<any> {
    const token = <string>sessionStorage.getItem('auth-token')
    for (let x of this.excludedUrl){
      if (request.url.includes(x)){
        return request;
      }
    }
    for (let x of this.includedList) {
      if (request.url.includes(x.url)){
        console.log('Bearer token added')
        return request.clone({
          headers: request.headers.set(this.TOKEN_HEADER_KEY, 'Bearer ' + token) 
        });
      }
    }
    return request;
  }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM