保持用户会话流畅的关键在于无需持续登录。本文将演示如何在 Angular 中实现令牌刷新流程,处理 401 错误并高效管理并发请求。
为了最大限度地降低安全风险,身份验证系统中的访问令牌通常具有较短的生命周期。当访问令牌过期时,刷新令牌允许应用程序在无需用户重新登录的情况下向服务器请求新的访问令牌。
我们将使用 Angular 的 HTTP 拦截器实现令牌刷新机制。其目标是在重试原始请求之前拦截未授权的请求(401 错误)并刷新令牌。
代码概述
handleUnauthorized
方法负责在请求因令牌过期而失败时刷新令牌。handleUnauthorized(req: HttpRequest<any>, next: HttpHandler): Observable<any> {
if (!this.isRefreshingToken) {
this.isRefreshingToken = true;
this.tokenSubject.next(null); // 通知所有等待请求令牌正在刷新
return this.refreshToken().pipe(
switchMap((newToken: string) => {
if (newToken) {
this.tokenSubject.next(newToken);
return next.handle(this.addToken(req, newToken)); // 使用新令牌重试原始请求
}
this.logout();
return throwError(() => '令牌过期');
}),
catchError((error) => {
this.logout();
return throwError(() => error);
}),
finalize(() => {
this.isRefreshingToken = false;
}),
);
} else {
// 令牌正在刷新时,将请求排队
return this.tokenSubject.pipe(
filter((token) => token !== null),
take(1),
switchMap((token) => next.handle(this.addToken(req, token))),
);
}
}
handleUnauthorized
函数处理 HTTP 请求收到 401 未授权状态码的情况(指示访问令牌过期或无效),确保应用程序可以刷新令牌并无缝重试失败的请求。
isRefreshingToken
标志确保一次只发出一个令牌刷新请求。如果令牌正在刷新,则后续请求将排队,直到新令牌可用。if (!this.isRefreshingToken) {
this.isRefreshingToken = true;
this.tokenSubject.next(null);
}
refreshToken
方法来启动令牌刷新。收到新令牌后:tokenSubject
中。return this.refreshToken().pipe(
switchMap((newToken: string) => {
// ...
})
);
tokenSubject
发出新令牌,然后继续。return this.tokenSubject.pipe(
filter((token) => token !== null),
take(1),
switchMap((token) => next.handle(this.addToken(req, token))),
);
catchError((error) => {
this.logout();
return throwError(() => error);
}),
finalize
运算符确保重置 isRefreshingToken
标志,以便允许后续刷新请求。finalize(() => {
this.isRefreshingToken = false;
}),
将令牌添加到请求:addToken
方法将新令牌附加到传出请求的标头中。
addToken(request: HttpRequest<any>, token: string): HttpRequest<any> {
return request.clone({
setHeaders: {
'x-token': token,
},
});
}
在 Angular HTTP 拦截器中使用:HTTP 拦截器是实现此流程的理想位置。它允许您拦截所有 HTTP 请求并全局处理令牌管理,而无需修改单个服务调用。
return next.handle(request).pipe(
catchError((error) => {
if (error.status === 401) {
return this.authService.handleUnauthorized(req, next);
}
return throwError(() => error);
}),
);
总之,一个健壮的令牌刷新流程确保 Angular 应用程序拥有流畅的用户体验和安全的会话管理。通过有效处理 401 错误并管理并发请求,您可以提高应用程序的可靠性和用户满意度。