首頁 > 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
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板