在 JWT 刷新时出现 401 时重定向

Posted

技术标签:

【中文标题】在 JWT 刷新时出现 401 时重定向【英文标题】:Redirecting in case of a 401 on JWT refreshing 【发布时间】:2020-07-01 22:36:45 【问题描述】:

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

我遵循了一个教程,该教程指导我使用刷新令牌制作 HTTPInterceptor 来刷新我的 JWT(如果它已过期)。我的令牌驻留在服务器设置的 cookie 中,因此不需要添加到标头中。

我的拦截器代码如下:

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 时,这可以很好地完成工作,但我还有另一个问题我找不到答案。

当我的刷新令牌过期/丢失时,我希望我的路由器重定向到登录页面。这基本上发生在路径/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 中没有刷新令牌,所以客户端可以检查它是否仍然存在并得出结论它不再被授权,但这对我来说似乎是一个安全漏洞。

【问题讨论】:

【参考方案1】:

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

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

【讨论】:

以上是关于在 JWT 刷新时出现 401 时重定向的主要内容,如果未能解决你的问题,请参考以下文章

RouterBrowser 不会在刷新时重定向到默认页面

在UpdateView上获取删除按钮以重定向时出现问题

React.js身份验证在每次刷新时重定向到登录名

如果用户登录 React 和 Typescript,则在刷新时重定向到仪表板

在 Vue.js 中捕获和重定向 JWT 令牌过期,而不阻塞 Vue 3 中的其他 401 错误

带有访客和身份验证中间件的 Nuxt 身份验证将经过身份验证的用户在刷新时重定向到错误的页面