简体   繁体   English

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

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

I'm working on an auth system in angular with a django backend with jwt. I have an angular interceptor which checks within every request if the access token is still valid and if not, it calls a refreshtoken function and refreshes the access token.我正在 angular 中的身份验证系统上工作,后端为 django,后端为 jwt。我有一个 angular 拦截器,它在每个请求中检查访问令牌是否仍然有效,如果无效,它会调用 refreshtoken function 并刷新访问令牌。

Here is the code of the interceptor:下面是拦截器的代码:

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);
    }

It gets the access_token and checks the validity with the help of the auth service.它获取 access_token 并在 auth 服务的帮助下检查有效性。 My problem is that if its unvalid its calls the refreshToken() function which looks like this,我的问题是,如果它无效,它调用 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"));
    });
  }

but it doesn't wait for the refresh token function to finish and returns the handle.但它不会等待刷新令牌 function 完成并返回句柄。 So the first request with an invalid token throws an error and only the next requests are fine.因此,带有无效令牌的第一个请求会抛出错误,只有下一个请求才正常。

How can I revise this to wait for refreshToken() to finish?我如何修改它以等待 refreshToken() 完成?

Thanks for your time!谢谢你的时间!

you can use rxjs operators such as switchMap您可以使用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);
    }
}

and in refreshToken function - make it return Observsble and set the localStorage inside piperefreshToken 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"));
});
 )
 }

I combined the answers from multiple questions and finally came up with this solution:我结合了多个问题的答案,最后想出了这个解决方案:

Interceptor:拦截器:

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);
    }
  }

refreshToken:刷新令牌:

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