在 HttpIntercopterFn 中使用来自 catchError 的新鲜 cookie

问题描述 投票:0回答:1

我创建了一个拦截器来确保每个请求都发送 HttpOnly jwt/refresh 令牌。我试图通过捕获 401 错误并请求服务器刷新来刷新我短暂的 jwt。它似乎正在工作,尽管可能不像我预期的那样。 这是我的代码:

export const jwtInterceptor: HttpInterceptorFn = (req, next) => {
  const router: Router = inject(Router);
  const authService: AuthService = inject(AuthService);

  req = req.clone({
    withCredentials: true,
  });

  return next(req).pipe(
    catchError((err: any) => {
      if (err instanceof HttpErrorResponse) {
        // Handle HTTP errors
        if (err.status === 401) {
          // handle unauthorized errors
          console.error('Unauthorized request:', err);
          // retry the request
          authService.refreshToken().subscribe({
            next: () => {
              authService.isRefreshed$.next(true);
            },
            error: () => {
              // Redirect to login page
              authService.logout(true);
              return router.createUrlTree(['/login'], {
                queryParams: { returnUrl: router.url },
              });
            },
          });
          return authService.isRefreshed$.pipe(switchMap(() => next(req)));
        } else {
          // Handle other HTTP error codes
          console.error('HTTP error:', err);
        }
      } else {
        // Handle non-HTTP errors
        console.error('An error occurred:', err);
      }
      // Re-throw the error to propagate it further
      return throwError(() => err);
    })
  );
};

当我通过开发人员工具查看网络调用时,看起来调用是按照我期望的顺序进行的。 cookie 已成功刷新,但未在重试请求中使用。我无法通过 TS 使用 HttpOnly cookie 修改请求,所以我不确定如何继续。

目标是使用刷新的 cookie 重试失败的请求。将来我会考虑缓存多个请求并在队列中重试它们。

angular rxjs jwt interceptor angular-http-interceptors
1个回答
0
投票

您代码中的问题是订阅中的代码是

asynchoronous
,而其下面的代码是
synchoronous
,因此底部代码不会等待主题具有值。


而是尝试下面的方法,他们使用

switchMap
来刷新单个流中的令牌(这消除了这个问题,因为 switchMap 将使流等待可观察到的刷新)在流的末尾,我们再次调用
next(req)
重新启动 API 调用或在刷新令牌失败时抛出错误。

确保仅在用户登录时调用刷新令牌

this.storageService.isLoggedIn()
,如果未经授权,则无需刷新逻辑。


您可以使用

bezkoder
中的本教程,指导您如何添加
refreshToken
逻辑。

带有拦截器和 JWT 的 Angular 12 刷新令牌示例(从链接中选择适当的 Angular 版本)

Bezkoder Github - http.interceptor.ts

export const jwtInterceptor: HttpInterceptorFn = (req, next) => {
  const router: Router = inject(Router);
  const authService: AuthService = inject(AuthService);
  let isRefreshing = false;
  req = req.clone({
    withCredentials: true,
  });

  const handle401Error = (isRefreshing: boolean, req: HttpRequest<any>, next: HttpHandler) => {
    if (isRefreshing) {
      isRefreshing = true;
      if (this.storageService.isLoggedIn()) {
        return this.authService.refreshToken().pipe(
          switchMap(() => {
            isRefreshing = false;
            return next(req);
          }),
          catchError((error) => {
            isRefreshing = false;
            // if (error.status == '403') {
            //   this.eventBusService.emit(new EventData('logout', null));
            // }
            return throwError(() => error);
          })
        );
      }
    }
    return next(req);
  };

  return next(req).pipe(
    catchError((error) => {
      if (
        error instanceof HttpErrorResponse &&
        !req.url.includes('auth/signin') &&
        error.status === 401
      ) {
        return handle401Error(isRefreshing, req, next);
      }
      return throwError(() => error);
    })
  );
};
© www.soinside.com 2019 - 2024. All rights reserved.