首页 > web前端 > js教程 > Angular 中刷新令牌

Angular 中刷新令牌

Patricia Arquette
发布: 2024-12-31 20:10:13
原创
505 人浏览过

在不持续登录的情况下维持用户会话是流畅网络体验的关键。在这篇博客中,我将向您展示如何在 Angular 中实现令牌刷新工作流程,处理 401 错误并有效管理并发请求。


什么是刷新令牌工作流程?

在身份验证系统中,访问令牌的生命周期较短,可以最大限度地降低安全风险。当访问令牌过期时,刷新令牌允许应用程序从服务器请求新的访问令牌,而不需要用户再次登录。


角度实施

我们将使用 Angular 的 HttpInterceptor 实现刷新令牌机制。目标是拦截未经授权的请求(401 错误)并在重试原始请求之前刷新令牌。


完整的工作流程

  • 请求拦截:
    拦截器检测到 401 未经授权的响应。

  • 令牌刷新:
    如果令牌过期,refreshToken 会获取新令牌。

  • 重试请求:
    使用新令牌重试原始请求。

  • 队列管理:
    刷新令牌后,将处理待处理的请求。

Refresh Token in Angular


代码概述

  1. 令牌刷新逻辑 当请求因令牌过期而失败时,handleUnauthorized 方法负责刷新令牌。
handleUnauthorized(
  req: HttpRequest<any>,
  next: HttpHandlerFn
): Observable<any> {
  if (!this.isRefreshingToken) {
    this.isRefreshingToken = true;

    // Notify all waiting requests that the token is being refreshed
    this.tokenSubject.next(null);

    return this.refreshToken().pipe(
      switchMap((newToken: string) => {
        if (newToken) {
          this.tokenSubject.next(newToken);
          // Retry the original request with the new token
          return next(this.addToken(req, newToken));
        }

        // If token refresh fails, log out the user
        this.logout();
        return throwError(() => 'Token expired');
      }),
      catchError((error) => {
        this.logout(); // Log out on error
        return throwError(() => error);
      }),
      finalize(() => {
        this.isRefreshingToken = false; // Reset the flag
      }),
    );
  } else {
    // Queue requests while a token is being refreshed
    return this.tokenSubject.pipe(
      filter((token) => token != null),
      take(1),
      switchMap((token) => next(this.addToken(req, token))),
    );
  }
}
登录后复制
登录后复制

handleUnauthorized 函数旨在管理 HTTP 请求收到 401 Unauthorized 状态(指示访问令牌已过期或无效)的场景。此功能确保应用程序可以刷新令牌并无缝重试失败的请求。

  1. 防止多次刷新请求 该函数使用 isRefreshingToken 标志来确保一次仅发出一个令牌刷新请求。如果令牌已被刷新,则后续请求将排队,直到新令牌可用。
handleUnauthorized(
  req: HttpRequest<any>,
  next: HttpHandlerFn
): Observable<any> {
  if (!this.isRefreshingToken) {
    this.isRefreshingToken = true;

    // Notify all waiting requests that the token is being refreshed
    this.tokenSubject.next(null);

    return this.refreshToken().pipe(
      switchMap((newToken: string) => {
        if (newToken) {
          this.tokenSubject.next(newToken);
          // Retry the original request with the new token
          return next(this.addToken(req, newToken));
        }

        // If token refresh fails, log out the user
        this.logout();
        return throwError(() => 'Token expired');
      }),
      catchError((error) => {
        this.logout(); // Log out on error
        return throwError(() => error);
      }),
      finalize(() => {
        this.isRefreshingToken = false; // Reset the flag
      }),
    );
  } else {
    // Queue requests while a token is being refreshed
    return this.tokenSubject.pipe(
      filter((token) => token != null),
      take(1),
      switchMap((token) => next(this.addToken(req, token))),
    );
  }
}
登录后复制
登录后复制
  1. 刷新令牌 如果没有刷新请求正在进行,它将使用refreshToken方法启动令牌刷新。收到新令牌后:
  • 它存储在 tokenSubject 中。
  • 使用更新后的令牌重试原始请求。
if (!this.isRefreshingToken) {
  this.isRefreshingToken = true;
  this.tokenSubject.next(null);

登录后复制
  1. 处理并发请求 如果令牌刷新已在进行中,则该函数会将后续请求排队。这些请求等待 tokenSubject 发出新令牌,然后再继续。
return this.refreshToken(url).pipe(
  switchMap((newToken: string) => {
    if (newToken) {
      this.tokenSubject.next(newToken);
      return next(this.addToken(req, newToken));
    }
    this.logout();
    return throwError(() => 'Token expired');
  }),

登录后复制
  1. 错误处理 如果令牌刷新失败或抛出异常:
  • 用户已注销。
  • 错误被返回给调用者。
return this.tokenSubject.pipe(
  filter((token) => token != null), // Wait for a non-null token
  take(1), // Only take the first emitted token
  switchMap((token) => next(this.addToken(req, token))),
);
登录后复制
  1. 清理 Finalize 运算符确保重置 isRefreshingToken 标志,从而允许后续刷新请求。
catchError((error) => {
  this.logout();
  return throwError(() => error);
}),

登录后复制

将令牌添加到请求
addToken 方法将新令牌附加到传出请求的标头中。

finalize(() => {
  this.isRefreshingToken = false;
}),
登录后复制

在 Angular HTTP 拦截器中使用它

HttpInterceptor 是实现此工作流程的完美场所。它允许您拦截所有 HTTP 请求并全局处理令牌管理,而无需修改单个服务调用。

addToken(request: HttpRequest<any>, token: string): HttpRequest<any> {
  return request.clone({
    setHeaders: {
      'X-Token': token,
    },
  });
}
登录后复制

总之,可靠的令牌刷新工作流程可确保 Angular 应用程序中的无缝用户体验和安全会话管理。通过有效处理 401 错误并管理并发请求,您可以保持可靠性并让用户满意。感谢您的阅读——请随时在下面分享您的想法或问题!

以上是Angular 中刷新令牌的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板