在Angular 8中,可以使用httpClient
和rxjs
库来实现在没有刷新令牌的情况下刷新令牌。以下是一个示例代码:
TokenInterceptor
拦截器,用于拦截每个请求并检查令牌是否过期:import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { Observable, BehaviorSubject, throwError } from 'rxjs';
import { catchError, filter, take, switchMap } from 'rxjs/operators';
import { AuthService } from './auth.service';
@Injectable()
export class TokenInterceptor implements HttpInterceptor {
private refreshTokenInProgress = false;
private refreshTokenSubject: BehaviorSubject = new BehaviorSubject(null);
constructor(public authService: AuthService) {}
intercept(request: HttpRequest, next: HttpHandler): Observable> {
request = this.addToken(request, this.authService.getAccessToken());
return next.handle(request).pipe(
catchError(error => {
if (error && error.status === 401) {
// 如果返回401未授权错误,则尝试刷新令牌
if (this.refreshTokenInProgress) {
// 如果在刷新令牌的过程中遇到多个请求返回401错误,则等待刷新完成再继续发送请求
return this.refreshTokenSubject.pipe(
filter(result => result !== null),
take(1),
switchMap(() => next.handle(this.addToken(request, this.authService.getAccessToken())))
);
} else {
this.refreshTokenInProgress = true;
// 刷新令牌
this.refreshTokenSubject.next(null);
return this.authService.refreshToken().pipe(
switchMap((token: any) => {
this.refreshTokenInProgress = false;
this.refreshTokenSubject.next(token.accessToken);
return next.handle(this.addToken(request, token.accessToken));
}),
catchError((err: any) => {
this.refreshTokenInProgress = false;
this.authService.logout();
return throwError(error);
})
);
}
} else {
return throwError(error);
}
})
);
}
addToken(request: HttpRequest, token: string): HttpRequest {
return request.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
}
}
AuthService
服务,用于处理令牌的获取和刷新:import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable()
export class AuthService {
private refreshTokenUrl = 'http://example.com/refresh-token';
constructor(private http: HttpClient) {}
getAccessToken(): string {
// 返回当前存储的访问令牌
return localStorage.getItem('accessToken');
}
refreshToken(): Observable {
// 发送刷新令牌的请求并返回新的令牌
return this.http.get(this.refreshTokenUrl);
}
logout(): void {
// 清除本地存储的令牌并重定向到登录页面
localStorage.removeItem('accessToken');
// redirect to login page
}
}
app.module.ts
中,将TokenInterceptor
拦截器添加到HTTP_INTERCEPTORS
提供者列表中:import { NgModule } from '@angular/core';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { TokenInterceptor } from './token.interceptor';
@NgModule({
imports: [HttpClientModule],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: TokenInterceptor,
multi: true
}
]
})
export class AppModule {}
通过以上步骤,每当发送请求时,TokenInterceptor
拦截器会检查令牌是否已过期。如果过期,则会尝试刷新令牌,并重新发送请求。如果刷新令牌失败或返回401错误,则用户将被注销并重定向到登录页面。