Angular 如何使用拦截器自动刷新访问令牌+;路障?

Angular 如何使用拦截器自动刷新访问令牌+;路障?,angular,jwt,Angular,Jwt,我浏览了大量的文章和问题,但似乎没有一篇涉及到拦截器中的自动令牌刷新,同时还有一个路由保护,它等待服务器完成请求,以验证访问令牌是否有效 auth.guard.ts canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | Url

我浏览了大量的文章和问题,但似乎没有一篇涉及到拦截器中的自动令牌刷新,同时还有一个路由保护,它等待服务器完成请求,以验证访问令牌是否有效

auth.guard.ts

canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {

    return this.authService.isAuthenticated()
      .pipe(
        map(
          res => {
            if (res.success === true) {
              return true;
            } else {
              this.authService.deleteToken();
              this.router.navigateByUrl('/login');
              return false;
            }
          }
        ), catchError(err => {
          // NOTE: If I put the code for refresh-token request here, it works -- user stays
          // logged in after getting new access token

          this.authService.deleteToken();
          this.router.navigate(['/login']);
          return of(false);
        })
      );
  }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (req.headers.get('noauth')) {
      return next.handle(req.clone());
    } else {
      const clonedReq = req.clone({
        headers: req.headers.set('Authorization', 'Bearer ' + this.authService.getToken())
      });

      return next.handle(clonedReq).pipe(
        tap(
          event => {},
          err => {
            if (err.error.code && err.error.code === 'EXPIRED') {
                return this.handle401Error(clonedReq, next);
            }
          }
        )
      );
    }
  }

  private handle401Error(request: HttpRequest<any>, next: HttpHandler) {
    if (!this.isRefreshing) {
      this.isRefreshing = true;
      this.refreshTokenSubject.next(null);

      return this.authService.refreshToken().pipe(
        switchMap((token: any) => {
          this.isRefreshing = false;
          this.refreshTokenSubject.next(token.new_access_token);
          return next.handle(this.addToken(request, token.new_access_token));
        }),
        catchError(err => {
          return throwError(err);
        }))
        .subscribe(r => r);

    } else {
      return this.refreshTokenSubject.pipe(
        filter(token => token != null),
        take(1),
        switchMap(jwt => {
          return next.handle(this.addToken(request, jwt));
        }));
    }
  }

  private addToken(request: HttpRequest<any>, token: string) {
    return request.clone({
      setHeaders: {
        'Authorization': `Bearer ${token}`
      }
    });
  }
refreshToken() {
    return this.http.post<any>(`${environment.api}/refresh-token`, {
      'refreshToken': this.getRefreshToken()
    }, this.noAuthHeader).pipe(tap((res) => {
      if (res.success === true) {
        this.setToken(res.new_access_token);
        return true;
      } else {
        this.deleteToken();
        this.router.navigateByUrl('/login');
        return false;
      }
    }));
  }
return this.authService.isAuthenticated()
      .pipe(
        map(
          res => {
            if (res.success === true) {
              return true;
            } else {
              this.authService.deleteToken();
              this.router.navigateByUrl('/login');
              return false;
            }
          }
        ), catchError(
          err => {

            // Absolutely needed this handler, 
            // but removed the code for redirection to login and deletion of tokens
            return of(false);
          }
        )
      );
return next.handle(clonedReq)
        .pipe(
          catchError((err: HttpErrorResponse) => {
            if (err.error.code === 'EXPIRED') {
                  return this.handle401Error(clonedReq, next);
            } else if (err.error.status === 401) {
                  this.router.navigateByUrl('/login');
                  return throwError(err.error.message);
            }

            // Redirect to an error landing page
            return throwError(err.error.message);
          })
        );

private handle401Error(request: HttpRequest<any>, next: HttpHandler) {

    if (!this.isRefreshing) {
      this.isRefreshing = true;
      this.refreshTokenSubject.next(null);

      return this.authService.refreshToken()
        .pipe(
          switchMap((token: any) => {
          this.refreshTokenSubject.next(token.new_access_token);
          this.authService.setToken(token.new_access_token);

          return next.handle(this.addToken(request, token.new_access_token));
        }), catchError(err => { 

          // .subscribe() not needed!Just an error handler
          if (err.error.code === 'EXPIRED') {
                this.authService.deleteToken();
                this.router.navigateByUrl('/login');
                return throwError(err.error.message);
          }
          
          // Redirect to error landing page
          return throwError(err.error.message);
      }),
      finalize(() => {
        this.isRefreshing = false;
      })
    );
...
canActivate(
路由:ActivatedRouteSnapshot,
状态:RouterStateSnashot):可观察的|承诺|布尔| UrlTree{
返回此.authService.isAuthenticated()
.烟斗(
地图(
res=>{
如果(res.success==true){
返回true;
}否则{
this.authService.deleteToken();
this.router.navigateByUrl('/login');
返回false;
}
}
),catchError(错误=>{
//注意:如果我把刷新令牌请求的代码放在这里,它就可以工作了——用户留下来
//获取新访问令牌后登录
this.authService.deleteToken();
this.router.navigate(['/login']);
归还(假);
})
);
}
auth.interceptor.ts

canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {

    return this.authService.isAuthenticated()
      .pipe(
        map(
          res => {
            if (res.success === true) {
              return true;
            } else {
              this.authService.deleteToken();
              this.router.navigateByUrl('/login');
              return false;
            }
          }
        ), catchError(err => {
          // NOTE: If I put the code for refresh-token request here, it works -- user stays
          // logged in after getting new access token

          this.authService.deleteToken();
          this.router.navigate(['/login']);
          return of(false);
        })
      );
  }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (req.headers.get('noauth')) {
      return next.handle(req.clone());
    } else {
      const clonedReq = req.clone({
        headers: req.headers.set('Authorization', 'Bearer ' + this.authService.getToken())
      });

      return next.handle(clonedReq).pipe(
        tap(
          event => {},
          err => {
            if (err.error.code && err.error.code === 'EXPIRED') {
                return this.handle401Error(clonedReq, next);
            }
          }
        )
      );
    }
  }

  private handle401Error(request: HttpRequest<any>, next: HttpHandler) {
    if (!this.isRefreshing) {
      this.isRefreshing = true;
      this.refreshTokenSubject.next(null);

      return this.authService.refreshToken().pipe(
        switchMap((token: any) => {
          this.isRefreshing = false;
          this.refreshTokenSubject.next(token.new_access_token);
          return next.handle(this.addToken(request, token.new_access_token));
        }),
        catchError(err => {
          return throwError(err);
        }))
        .subscribe(r => r);

    } else {
      return this.refreshTokenSubject.pipe(
        filter(token => token != null),
        take(1),
        switchMap(jwt => {
          return next.handle(this.addToken(request, jwt));
        }));
    }
  }

  private addToken(request: HttpRequest<any>, token: string) {
    return request.clone({
      setHeaders: {
        'Authorization': `Bearer ${token}`
      }
    });
  }
refreshToken() {
    return this.http.post<any>(`${environment.api}/refresh-token`, {
      'refreshToken': this.getRefreshToken()
    }, this.noAuthHeader).pipe(tap((res) => {
      if (res.success === true) {
        this.setToken(res.new_access_token);
        return true;
      } else {
        this.deleteToken();
        this.router.navigateByUrl('/login');
        return false;
      }
    }));
  }
return this.authService.isAuthenticated()
      .pipe(
        map(
          res => {
            if (res.success === true) {
              return true;
            } else {
              this.authService.deleteToken();
              this.router.navigateByUrl('/login');
              return false;
            }
          }
        ), catchError(
          err => {

            // Absolutely needed this handler, 
            // but removed the code for redirection to login and deletion of tokens
            return of(false);
          }
        )
      );
return next.handle(clonedReq)
        .pipe(
          catchError((err: HttpErrorResponse) => {
            if (err.error.code === 'EXPIRED') {
                  return this.handle401Error(clonedReq, next);
            } else if (err.error.status === 401) {
                  this.router.navigateByUrl('/login');
                  return throwError(err.error.message);
            }

            // Redirect to an error landing page
            return throwError(err.error.message);
          })
        );

private handle401Error(request: HttpRequest<any>, next: HttpHandler) {

    if (!this.isRefreshing) {
      this.isRefreshing = true;
      this.refreshTokenSubject.next(null);

      return this.authService.refreshToken()
        .pipe(
          switchMap((token: any) => {
          this.refreshTokenSubject.next(token.new_access_token);
          this.authService.setToken(token.new_access_token);

          return next.handle(this.addToken(request, token.new_access_token));
        }), catchError(err => { 

          // .subscribe() not needed!Just an error handler
          if (err.error.code === 'EXPIRED') {
                this.authService.deleteToken();
                this.router.navigateByUrl('/login');
                return throwError(err.error.message);
          }
          
          // Redirect to error landing page
          return throwError(err.error.message);
      }),
      finalize(() => {
        this.isRefreshing = false;
      })
    );
...
intercept(req:HttpRequest,next:HttpHandler):可观察{
if(req.headers.get('noauth')){
返回next.handle(req.clone());
}否则{
const clonedReq=req.clone({
headers:req.headers.set('Authorization','Bearer'+this.authService.getToken())
});
返回next.handle(clonedReq).pipe(
水龙头(
事件=>{},
错误=>{
如果(err.error.code&&err.error.code==='EXPIRED'){
返回此.handle401错误(clonedReq,下一个);
}
}
)
);
}
}
私有句柄401错误(请求:HttpRequest,下一个:HttpHandler){
如果(!this.isRefreshing){
this.isRefreshing=true;
this.refreshTokenSubject.next(null);
返回此.authService.refreshToken()管道(
开关映射((令牌:任意)=>{
this.isRefreshing=false;
this.refreshTokenSubject.next(token.new\u access\u token);
返回next.handle(this.addToken(request,token.new_access_token));
}),
catchError(err=>{
回程抛掷器(err);
}))
.认购(r=>r);
}否则{
返回此.refreshTokenSubject.pipe(
过滤器(令牌=>令牌!=null),
以(1)为例,
开关映射(jwt=>{
返回next.handle(this.addToken(request,jwt));
}));
}
}
私有addToken(请求:HttpRequest,令牌:string){
return request.clone({
集合标题:{
'Authorization':'Bearer${token}`
}
});
}
auth.service.ts

canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {

    return this.authService.isAuthenticated()
      .pipe(
        map(
          res => {
            if (res.success === true) {
              return true;
            } else {
              this.authService.deleteToken();
              this.router.navigateByUrl('/login');
              return false;
            }
          }
        ), catchError(err => {
          // NOTE: If I put the code for refresh-token request here, it works -- user stays
          // logged in after getting new access token

          this.authService.deleteToken();
          this.router.navigate(['/login']);
          return of(false);
        })
      );
  }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (req.headers.get('noauth')) {
      return next.handle(req.clone());
    } else {
      const clonedReq = req.clone({
        headers: req.headers.set('Authorization', 'Bearer ' + this.authService.getToken())
      });

      return next.handle(clonedReq).pipe(
        tap(
          event => {},
          err => {
            if (err.error.code && err.error.code === 'EXPIRED') {
                return this.handle401Error(clonedReq, next);
            }
          }
        )
      );
    }
  }

  private handle401Error(request: HttpRequest<any>, next: HttpHandler) {
    if (!this.isRefreshing) {
      this.isRefreshing = true;
      this.refreshTokenSubject.next(null);

      return this.authService.refreshToken().pipe(
        switchMap((token: any) => {
          this.isRefreshing = false;
          this.refreshTokenSubject.next(token.new_access_token);
          return next.handle(this.addToken(request, token.new_access_token));
        }),
        catchError(err => {
          return throwError(err);
        }))
        .subscribe(r => r);

    } else {
      return this.refreshTokenSubject.pipe(
        filter(token => token != null),
        take(1),
        switchMap(jwt => {
          return next.handle(this.addToken(request, jwt));
        }));
    }
  }

  private addToken(request: HttpRequest<any>, token: string) {
    return request.clone({
      setHeaders: {
        'Authorization': `Bearer ${token}`
      }
    });
  }
refreshToken() {
    return this.http.post<any>(`${environment.api}/refresh-token`, {
      'refreshToken': this.getRefreshToken()
    }, this.noAuthHeader).pipe(tap((res) => {
      if (res.success === true) {
        this.setToken(res.new_access_token);
        return true;
      } else {
        this.deleteToken();
        this.router.navigateByUrl('/login');
        return false;
      }
    }));
  }
return this.authService.isAuthenticated()
      .pipe(
        map(
          res => {
            if (res.success === true) {
              return true;
            } else {
              this.authService.deleteToken();
              this.router.navigateByUrl('/login');
              return false;
            }
          }
        ), catchError(
          err => {

            // Absolutely needed this handler, 
            // but removed the code for redirection to login and deletion of tokens
            return of(false);
          }
        )
      );
return next.handle(clonedReq)
        .pipe(
          catchError((err: HttpErrorResponse) => {
            if (err.error.code === 'EXPIRED') {
                  return this.handle401Error(clonedReq, next);
            } else if (err.error.status === 401) {
                  this.router.navigateByUrl('/login');
                  return throwError(err.error.message);
            }

            // Redirect to an error landing page
            return throwError(err.error.message);
          })
        );

private handle401Error(request: HttpRequest<any>, next: HttpHandler) {

    if (!this.isRefreshing) {
      this.isRefreshing = true;
      this.refreshTokenSubject.next(null);

      return this.authService.refreshToken()
        .pipe(
          switchMap((token: any) => {
          this.refreshTokenSubject.next(token.new_access_token);
          this.authService.setToken(token.new_access_token);

          return next.handle(this.addToken(request, token.new_access_token));
        }), catchError(err => { 

          // .subscribe() not needed!Just an error handler
          if (err.error.code === 'EXPIRED') {
                this.authService.deleteToken();
                this.router.navigateByUrl('/login');
                return throwError(err.error.message);
          }
          
          // Redirect to error landing page
          return throwError(err.error.message);
      }),
      finalize(() => {
        this.isRefreshing = false;
      })
    );
...
refreshToken(){
返回此.http.post(`${environment.api}/refresh-token`{
“refreshToken”:this.getRefreshToken()
}管道(水龙头((分辨率)=>{
如果(res.success==true){
this.setToken(res.new\u access\u token);
返回true;
}否则{
this.deleteToken();
this.router.navigateByUrl('/login');
返回false;
}
}));
}

发生的情况是:

  • 用户尝试访问安全路由
  • auth.guard.ts向服务器发送请求以验证访问令牌的有效性
  • 访问令牌已过期,因此服务器以401响应
  • 刷新令牌的请求将被发送,但验证访问令牌的初始请求将首先完成——用户将被重定向到登录页面,而不是保持登录状态
  • 刷新令牌的请求完成

  • 我不确定这是怎么发生的,但我想的是,获取新访问令牌的请求应该首先完成,然后身份验证请求/auth.guard应该以此为基础?

    在被卡住一天半后,我想我终于自己解决了它:

    auth.guard.ts

    canActivate(
        route: ActivatedRouteSnapshot,
        state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
    
        return this.authService.isAuthenticated()
          .pipe(
            map(
              res => {
                if (res.success === true) {
                  return true;
                } else {
                  this.authService.deleteToken();
                  this.router.navigateByUrl('/login');
                  return false;
                }
              }
            ), catchError(err => {
              // NOTE: If I put the code for refresh-token request here, it works -- user stays
              // logged in after getting new access token
    
              this.authService.deleteToken();
              this.router.navigate(['/login']);
              return of(false);
            })
          );
      }
    
    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        if (req.headers.get('noauth')) {
          return next.handle(req.clone());
        } else {
          const clonedReq = req.clone({
            headers: req.headers.set('Authorization', 'Bearer ' + this.authService.getToken())
          });
    
          return next.handle(clonedReq).pipe(
            tap(
              event => {},
              err => {
                if (err.error.code && err.error.code === 'EXPIRED') {
                    return this.handle401Error(clonedReq, next);
                }
              }
            )
          );
        }
      }
    
      private handle401Error(request: HttpRequest<any>, next: HttpHandler) {
        if (!this.isRefreshing) {
          this.isRefreshing = true;
          this.refreshTokenSubject.next(null);
    
          return this.authService.refreshToken().pipe(
            switchMap((token: any) => {
              this.isRefreshing = false;
              this.refreshTokenSubject.next(token.new_access_token);
              return next.handle(this.addToken(request, token.new_access_token));
            }),
            catchError(err => {
              return throwError(err);
            }))
            .subscribe(r => r);
    
        } else {
          return this.refreshTokenSubject.pipe(
            filter(token => token != null),
            take(1),
            switchMap(jwt => {
              return next.handle(this.addToken(request, jwt));
            }));
        }
      }
    
      private addToken(request: HttpRequest<any>, token: string) {
        return request.clone({
          setHeaders: {
            'Authorization': `Bearer ${token}`
          }
        });
      }
    
    refreshToken() {
        return this.http.post<any>(`${environment.api}/refresh-token`, {
          'refreshToken': this.getRefreshToken()
        }, this.noAuthHeader).pipe(tap((res) => {
          if (res.success === true) {
            this.setToken(res.new_access_token);
            return true;
          } else {
            this.deleteToken();
            this.router.navigateByUrl('/login');
            return false;
          }
        }));
      }
    
    return this.authService.isAuthenticated()
          .pipe(
            map(
              res => {
                if (res.success === true) {
                  return true;
                } else {
                  this.authService.deleteToken();
                  this.router.navigateByUrl('/login');
                  return false;
                }
              }
            ), catchError(
              err => {
    
                // Absolutely needed this handler, 
                // but removed the code for redirection to login and deletion of tokens
                return of(false);
              }
            )
          );
    
    return next.handle(clonedReq)
            .pipe(
              catchError((err: HttpErrorResponse) => {
                if (err.error.code === 'EXPIRED') {
                      return this.handle401Error(clonedReq, next);
                } else if (err.error.status === 401) {
                      this.router.navigateByUrl('/login');
                      return throwError(err.error.message);
                }
    
                // Redirect to an error landing page
                return throwError(err.error.message);
              })
            );
    
    private handle401Error(request: HttpRequest<any>, next: HttpHandler) {
    
        if (!this.isRefreshing) {
          this.isRefreshing = true;
          this.refreshTokenSubject.next(null);
    
          return this.authService.refreshToken()
            .pipe(
              switchMap((token: any) => {
              this.refreshTokenSubject.next(token.new_access_token);
              this.authService.setToken(token.new_access_token);
    
              return next.handle(this.addToken(request, token.new_access_token));
            }), catchError(err => { 
    
              // .subscribe() not needed!Just an error handler
              if (err.error.code === 'EXPIRED') {
                    this.authService.deleteToken();
                    this.router.navigateByUrl('/login');
                    return throwError(err.error.message);
              }
              
              // Redirect to error landing page
              return throwError(err.error.message);
          }),
          finalize(() => {
            this.isRefreshing = false;
          })
        );
    ...
    
    auth.interceptor.ts

    canActivate(
        route: ActivatedRouteSnapshot,
        state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
    
        return this.authService.isAuthenticated()
          .pipe(
            map(
              res => {
                if (res.success === true) {
                  return true;
                } else {
                  this.authService.deleteToken();
                  this.router.navigateByUrl('/login');
                  return false;
                }
              }
            ), catchError(err => {
              // NOTE: If I put the code for refresh-token request here, it works -- user stays
              // logged in after getting new access token
    
              this.authService.deleteToken();
              this.router.navigate(['/login']);
              return of(false);
            })
          );
      }
    
    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        if (req.headers.get('noauth')) {
          return next.handle(req.clone());
        } else {
          const clonedReq = req.clone({
            headers: req.headers.set('Authorization', 'Bearer ' + this.authService.getToken())
          });
    
          return next.handle(clonedReq).pipe(
            tap(
              event => {},
              err => {
                if (err.error.code && err.error.code === 'EXPIRED') {
                    return this.handle401Error(clonedReq, next);
                }
              }
            )
          );
        }
      }
    
      private handle401Error(request: HttpRequest<any>, next: HttpHandler) {
        if (!this.isRefreshing) {
          this.isRefreshing = true;
          this.refreshTokenSubject.next(null);
    
          return this.authService.refreshToken().pipe(
            switchMap((token: any) => {
              this.isRefreshing = false;
              this.refreshTokenSubject.next(token.new_access_token);
              return next.handle(this.addToken(request, token.new_access_token));
            }),
            catchError(err => {
              return throwError(err);
            }))
            .subscribe(r => r);
    
        } else {
          return this.refreshTokenSubject.pipe(
            filter(token => token != null),
            take(1),
            switchMap(jwt => {
              return next.handle(this.addToken(request, jwt));
            }));
        }
      }
    
      private addToken(request: HttpRequest<any>, token: string) {
        return request.clone({
          setHeaders: {
            'Authorization': `Bearer ${token}`
          }
        });
      }
    
    refreshToken() {
        return this.http.post<any>(`${environment.api}/refresh-token`, {
          'refreshToken': this.getRefreshToken()
        }, this.noAuthHeader).pipe(tap((res) => {
          if (res.success === true) {
            this.setToken(res.new_access_token);
            return true;
          } else {
            this.deleteToken();
            this.router.navigateByUrl('/login');
            return false;
          }
        }));
      }
    
    return this.authService.isAuthenticated()
          .pipe(
            map(
              res => {
                if (res.success === true) {
                  return true;
                } else {
                  this.authService.deleteToken();
                  this.router.navigateByUrl('/login');
                  return false;
                }
              }
            ), catchError(
              err => {
    
                // Absolutely needed this handler, 
                // but removed the code for redirection to login and deletion of tokens
                return of(false);
              }
            )
          );
    
    return next.handle(clonedReq)
            .pipe(
              catchError((err: HttpErrorResponse) => {
                if (err.error.code === 'EXPIRED') {
                      return this.handle401Error(clonedReq, next);
                } else if (err.error.status === 401) {
                      this.router.navigateByUrl('/login');
                      return throwError(err.error.message);
                }
    
                // Redirect to an error landing page
                return throwError(err.error.message);
              })
            );
    
    private handle401Error(request: HttpRequest<any>, next: HttpHandler) {
    
        if (!this.isRefreshing) {
          this.isRefreshing = true;
          this.refreshTokenSubject.next(null);
    
          return this.authService.refreshToken()
            .pipe(
              switchMap((token: any) => {
              this.refreshTokenSubject.next(token.new_access_token);
              this.authService.setToken(token.new_access_token);
    
              return next.handle(this.addToken(request, token.new_access_token));
            }), catchError(err => { 
    
              // .subscribe() not needed!Just an error handler
              if (err.error.code === 'EXPIRED') {
                    this.authService.deleteToken();
                    this.router.navigateByUrl('/login');
                    return throwError(err.error.message);
              }
              
              // Redirect to error landing page
              return throwError(err.error.message);
          }),
          finalize(() => {
            this.isRefreshing = false;
          })
        );
    ...
    
    返回下一个.handle(clonedReq)
    .烟斗(
    catchError((错误:HttpErrorResponse)=>{
    如果(err.error.code==‘过期’){
    返回此.handle401错误(clonedReq,下一个);
    }else if(err.error.status==401){
    this.router.navigateByUrl('/login');
    返回抛出器(err.error.message);
    }
    //重定向到错误登录页
    返回抛出器(err.error.message);
    })
    );
    私有句柄401错误(请求:HttpRequest,下一个:HttpHandler){
    如果(!this.isRefreshing){
    this.isRefreshing=true;
    this.refreshTokenSubject.next(null);
    返回此.authService.refreshToken()
    .烟斗(
    开关映射((令牌:任意)=>{
    this.refreshTokenSubject.next(token.new\u access\u token);
    this.authService.setToken(token.new\u access\u token);
    返回next.handle(this.addToken(request,token.new_access_token));
    }),catchError(err=>{
    //.subscribe()不需要!只是一个错误处理程序
    如果(err.error.code==‘过期’){
    this.authService.deleteToken();
    this.router.navigateByUrl('/login');
    返回抛出器(err.error.message);
    }
    //重定向到错误登录页
    返回抛出器(err.error.message);
    }),
    完成(()=>{
    this.isRefreshing=false;
    })
    );
    ...
    

    我希望这对您有所帮助!

    当您在
    refreshttoken()
    方法中删除旧令牌并导航到登录页面时,为什么在
    isAuthenticated()中出现完全
    catchError
    又来了?嗨@roya,如果我没听错的话,你是说我不需要
    auth.guard
    中的
    catchError
    ?我实际上刚刚试过,但我得到了一个错误:
    错误:未捕获(I