保持用户会话流畅的关键在于无需持续登录。本文将演示如何在 angular 中实现令牌刷新流程,处理 401 错误并高效管理并发请求。
什么是令牌刷新流程?
为了最大限度地降低安全风险,身份验证系统中的访问令牌通常具有较短的生命周期。当访问令牌过期时,刷新令牌允许应用程序在无需用户重新登录的情况下向服务器请求新的访问令牌。
Angular 实现
我们将使用 Angular 的 HTTP 拦截器实现令牌刷新机制。其目标是在重试原始请求之前拦截未授权的请求(401 错误)并刷新令牌。
完整流程
- 请求拦截:拦截器检测到 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 错误并管理并发请求,您可以提高应用程序的可靠性和用户满意度。
本文采摘于网络,不代表本站立场,转载联系作者并注明出处:https://www.iotsj.com//kuaixun/8239.html