Angular 中的刷新令牌
无需不断登录即可维护用户会话是顺畅的 Web 体验的关键。在本博客中,我将向您展示如何在 Angular 中实现令牌刷新工作流、处理 401 错误并有效管理并发请求。
什么是刷新令牌工作流?
在身份验证系统中,访问令牌的有效期较短,以最大限度地降低安全风险。当访问令牌过期时,刷新令牌允许应用程序从服务器请求新的访问令牌,而无需用户再次登录。
角度实施
我们将使用 Angular 的 `HttpInterceptor` 实现刷新令牌机制。目标是拦截未经授权的请求(401 错误)并在重试原始请求之前刷新令牌。
完整的工作流程

代码概述
handleUnauthorized( req: HttpRequest, next: HttpHandlerFn ): Observable { 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 状态的情况,表示访问令牌已过期或无效。此函数可确保应用程序可以刷新令牌并无缝重试失败的请求。
if (!this.isRefreshingToken) {
this.isRefreshingToken = true;
this.tokenSubject.next(null);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');
}),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))), );
catchError((error) => {
this.logout();
return throwError(() => error);
}),finalize(() => {
this.isRefreshingToken = false;
}),将令牌添加到请求
addToken 方法将新令牌附加到传出请求的标头。
addToken(request: HttpRequest, token: string): HttpRequest { return request.clone({ setHeaders: { 'X-Token': token, }, }); }
在 Angular HTTP 拦截器中使用它
`HttpInterceptor` 是实现此工作流程的理想场所。它允许您拦截所有 HTTP 请求并全局处理令牌管理,而无需修改单个服务调用。
return next.handle(request).pipe(
catchError((error) => {
if (error.status === 401) {
return this.authService.handleUnauthorized(req, next);
}
return throwError(() => error);
}),
);总而言之,可靠的令牌刷新工作流可确保 Angular 应用程序中的无缝用户体验和安全会话管理。通过有效处理 401 错误并管理并发请求,您可以保持可靠性并让用户满意。感谢您的阅读——欢迎在下面分享您的想法或问题!