Javascript 跨选项卡计划访问令牌刷新
为了对Angular应用程序中的用户进行身份验证,我使用到期时间为X秒的访问令牌和可用于将身份验证再延长X秒的刷新令牌 所以流程是这样的:Javascript 跨选项卡计划访问令牌刷新,javascript,angular,Javascript,Angular,为了对Angular应用程序中的用户进行身份验证,我使用到期时间为X秒的访问令牌和可用于将身份验证再延长X秒的刷新令牌 所以流程是这样的: 用户登录。访问和刷新令牌都存储在本地存储器中 设置计时器(比X秒短5%) 计时器完成后,将向服务器发送刷新令牌请求,并使用生成的(新)访问和刷新令牌更新本地存储 我的问题是: 如果我打开了多个选项卡,我将不可避免地在多个选项卡同时触发刷新的情况下结束。服务器将接受第一个请求,但对后续请求抛出400错误请求-无效刷新令牌,因为它认为这些请求已被使用 有
- 用户登录。访问和刷新令牌都存储在本地存储器中
- 设置计时器(比X秒短5%)
- 计时器完成后,将向服务器发送刷新令牌请求,并使用生成的(新)访问和刷新令牌更新本地存储李>
- 如果我打开了多个选项卡,我将不可避免地在多个选项卡同时触发刷新的情况下结束。服务器将接受第一个请求,但对后续请求抛出
,因为它认为这些请求已被使用400错误请求-无效刷新令牌
- 如果响应是
,请稍后重试(或检查是否已经有有效的更新令牌)400错误请求
- 通过在选项卡之间发布消息,尝试跨选项卡同步服务器请求
intercept(request: HttpRequest<any>, next: HttpHandler):
Observable<HttpEvent<any>> {
return next.handle(request).pipe(
catchError((error: HttpErrorResponse) => {
if (error.status == 401) {
return this.refreshToken(request, next);
}
}
return throwError(error);
})
);
private refreshingInProgress: boolean = false;
private accessTokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);
private refreshToken(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (!this.refreshingInProgress) {
this.refreshingInProgress = true;
this.accessTokenSubject.next(null);
return this.authenticationService.refreshToken().pipe(
switchMap((res: any) => {
this.refreshingInProgress = false;
this.accessTokenSubject.next(res);
// repeat failed request with new token
return next.handle(this.addToken(request, res));
})
);
} else {
// wait while getting new token
return this.accessTokenSubject.pipe(
filter((token) => token !== null),
take(1),
switchMap((token) => {
// repeat failed request with new token
return next.handle(this.addToken(request, token));
})
);
}
}
private addToken(request: HttpRequest<any>, token: Credentials) {
return request.clone({
setHeaders: {
Authorization: `Bearer ${token.access_token}`,
},
});
}
intercept(请求:HttpRequest,下一步:HttpHandler):
可观察{
返回next.handle(request.pipe)(
catchError((错误:HttpErrorResponse)=>{
如果(error.status==401){
返回此.refreshToken(请求,下一步);
}
}
返回投掷器(错误);
})
);
私有刷新进度:布尔值=false;
private accessTokenSubject:BehaviorSubject=new BehaviorSubject(null);
私有刷新令牌(请求:HttpRequest,下一步:HttpHandler):可观察{
如果(!this.refreshingProgress){
this.refreshingProgress=true;
this.accessTokenSubject.next(null);
返回此.authenticationService.refreshToken()管道(
开关映射((res:any)=>{
this.refreshingProgress=false;
this.accessTokenSubject.next(res);
//使用新令牌重复失败的请求
返回next.handle(this.addToken(request,res));
})
);
}否则{
//正在获取新令牌,请稍候
返回此.accessTokenSubject.pipe(
过滤器((令牌)=>令牌!==null),
以(1)为例,
开关映射((令牌)=>{
//使用新令牌重复失败的请求
返回next.handle(this.addToken(request,token));
})
);
}
}
私有addToken(请求:HttpRequest,令牌:凭据){
return request.clone({
集合标题:{
授权:`Bearer${token.access_token}`,
},
});
}
这可能会对您有所帮助