在 JWT 刷新 401 的情况下重定向

Redirecting in case of a 401 on JWT refreshing

我目前正在开发 Angular 9 应用程序,在后端使用 JWT 身份验证。

我遵循了指导我制作 HTTPInterceptor 的教程,以便在 JWT 过期时使用刷新令牌刷新我的 JWT。我的令牌驻留在服务器设置的 cookie 中,因此不需要添加到 headers.

我的拦截器代码如下:

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<any> {
  console.log("Intercepted!");
  return next.handle(req).pipe(
    catchError((error: HttpErrorResponse) => {
      console.log("Error seen");
      if (error && error.status === 401) {
        // 401 errors are most likely going to be because we have an expired token that we need to refresh.
        if (this.refreshing) {
          console.log("Already refreshing");
          // 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(req))
          );
        } else {
          this.refreshing = 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.authService.refreshToken().pipe(
            switchMap((success: boolean) => {
              this.refreshTokenSubject.next(success);
              return next.handle(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.refreshing = false)
          );
        }
      } else {
        return throwError(error);
      }
    })
  );
}

这在刷新 JWT 时工作得很好,但我有另一个问题我找不到答案。

当我的刷新令牌为 expired/missing 时,我希望我的路由器重定向到登录页面。这基本上发生在路径 /api/token/refresh 上返回 401 时。如您所见,我添加了一些日志,当从受保护的 URL 获取时,输出如下:

sendGet
to: /api/test
authconfig.interceptor.ts:27 Intercepted!
GET https://localhost:8000/api/test 401
authconfig.interceptor.ts:30 Error seen
auth.service.ts:43 Refreshing token using refreshtoken from AuthService.
authconfig.interceptor.ts:27 Intercepted!
VM1101:1 GET https://localhost:8000/api/token/refresh 401
authconfig.interceptor.ts:30 Error seen
authconfig.interceptor.ts:34 Already refreshing

拦截器认为它仍在刷新,因为它从未从服务器尝试刷新令牌中收到正确的响应。如果是第二个 GET,这将是适当的响应,我不知道如何区分两者。我想过添加一个功能来检查我是否仍然通过 GETting 从 /api/token/refresh 登录,但它显然也只是被拦截和保留。

执行此操作的明智方法是什么?我考虑过在 httponly cookie 中没有刷新令牌,因此客户端可以检查它是否仍然存在并得出结论认为它不再被授权,但这对我来说似乎是一个安全漏洞。

我已经能够自己解决这个问题。通过在将请求放入队列之前检查刷新令牌的 URL 是否在请求中,可以检测到刷新令牌丢失。毕竟,只有请求token刷新路径返回401,表示没有token,才会出现这一系列事件。

如果请求路径中包含刷新令牌的URL,我们可以重定向。