繁体   English   中英

Angular - 在转发请求之前等待刷新令牌 function 完成

[英]Angular - Waiting for refresh token function to finish before forwarding the request

我正在 angular 中的身份验证系统上工作,后端为 django,后端为 jwt。我有一个 angular 拦截器,它在每个请求中检查访问令牌是否仍然有效,如果无效,它会调用 refreshtoken function 并刷新访问令牌。

下面是拦截器的代码:

constructor(private authService:AuthService) {}

  intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
    let access_token = localStorage.getItem("access_token");
    
    if(access_token){
      // Check if access token is no longer valid, if so, refresh it with the refresh token
      if(this.authService.isLoggedOut()){
        
        this.authService.refreshToken();
        access_token = localStorage.getItem("access_token");
      }
      const cloned = request.clone({
        headers: request.headers.set("Authorization", "Bearer " + access_token)
      });
      return next.handle(cloned);
    } 
    else{
      return next.handle(request);
    }

它获取 access_token 并在 auth 服务的帮助下检查有效性。 我的问题是,如果它无效,它调用 refreshToken() function 看起来像这样,

  refreshToken(){
    let refresh_token = localStorage.getItem("refresh_token");
    console.log("BEFORE REFRESH: " + localStorage.getItem("access_token"));
 
    return this.http.post(`${apiUrl}token/refresh/`, {"refresh" : refresh_token}).subscribe(res => {
      let access_token = res["access"]
      const expiresAt = this.tokenExpiresAt(access_token);
      localStorage.setItem("access_token", access_token);
      localStorage.setItem("expires_at", JSON.stringify(expiresAt.valueOf()));

      console.log("AFTER REFRESH: " + localStorage.getItem("access_token"));
    });
  }

但它不会等待刷新令牌 function 完成并返回句柄。 因此,带有无效令牌的第一个请求会抛出错误,只有下一个请求才正常。

我如何修改它以等待 refreshToken() 完成?

谢谢你的时间!

您可以使用rxjs运算符,例如switchMap

    intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
    let access_token = localStorage.getItem("access_token");
    if (access_token) {
        // Check if access token is no longer valid, if so, refresh it with the refresh token
        if (this.authService.isLoggedOut()) {
            return this.authService.refreshToken().pipe(
                switchMap(token => {
                    const cloned = request.clone({
                        headers: request.headers.set("Authorization", "Bearer " + access_token)
                    });
                    return next.handle(cloned);
                })
            )
        }
    } else {
        return next.handle(request);
    }
}

refreshToken function - 让它返回Observsble并在pipe中设置localStorage

refreshToken(){
let refresh_token = localStorage.getItem("refresh_token");
console.log("BEFORE REFRESH: " + localStorage.getItem("access_token"));

return this.http.post(`${apiUrl}token/refresh/`, {"refresh" : refresh_token}).pipe(tap(res => {
  let access_token = res["access"]
  const expiresAt = this.tokenExpiresAt(access_token);
  localStorage.setItem("access_token", access_token);
  localStorage.setItem("expires_at", JSON.stringify(expiresAt.valueOf()));

  console.log("AFTER REFRESH: " + localStorage.getItem("access_token"));
});
 )
 }

我结合了多个问题的答案,最后想出了这个解决方案:

拦截器:

intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
    let access_token = localStorage.getItem("access_token");
  
    if (access_token) {
      // Check if access token is no longer valid, if so, refresh it with the refresh token
      if (this.authService.isLoggedOut()) {
        return from(this.authService.refreshToken()).pipe(
          mergeMap((access_token) => {
            localStorage.setItem("access_token", access_token);
            const cloned = request.clone({
              headers: request.headers.set("Authorization", "Bearer " + access_token),
            });
            return next.handle(cloned);
          })
        );
      }
      const cloned = request.clone({
        headers: request.headers.set("Authorization", "Bearer " + access_token),
      });
      return next.handle(cloned);
    } else {
      return next.handle(request);
    }
  }

刷新令牌:

async refreshToken(): Promise<string> {
    let refresh_token = localStorage.getItem("refresh_token"); 
    const res$ = this.http
    .post(`${apiUrl}token/refresh/`, { refresh: refresh_token })
    .pipe(map((res) => res["access"]))
    .pipe(first());
    const res = await lastValueFrom(res$);

    const expiresAt = this.tokenExpiresAt(res);
    localStorage.setItem("access_token", res);
    localStorage.setItem("expires_at", JSON.stringify(expiresAt.valueOf()));
    console.log("Refreshed Access Token");
    return res;
  }

暂无
暂无

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

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