Angular 角度:仅刷新令牌一次

Angular 角度:仅刷新令牌一次,angular,rxjs,observable,Angular,Rxjs,Observable,我使用JWT和刷新令牌策略作为身份验证,我的Angular客户端中有一个拦截器,它将令牌作为头发送 我在发送前检查过期时间,如果需要,用我的refreshToken刷新令牌 问题是当发送2个(或更多)请求时,两个请求都试图刷新令牌。我需要一个函数,它发送req请求刷新令牌,当一次调用多次时,只向服务器发出1个http req请求刷新,并将新更新的令牌返回给所有调用它的人 这是我的拦截器: intercept(req: HttpRequest<any>, next: HttpHan

我使用JWT和刷新令牌策略作为身份验证,我的Angular客户端中有一个拦截器,它将令牌作为头发送

我在发送前检查过期时间,如果需要,用我的refreshToken刷新令牌

问题是当发送2个(或更多)请求时,两个请求都试图刷新令牌。我需要一个函数,它发送req请求刷新令牌,当一次调用多次时,只向服务器发出1个http req请求刷新,并将新更新的令牌返回给所有调用它的人

这是我的拦截器:

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const authService = this.inj.get(AuthService);
    const token = authService.getToken();

    // if no token or this is a refresh token req
    if (!token || req.url.split('/').pop() === 'refreshToken') {
      return next.handle(req);
    }

    const decoded = jwt.decode(token);

    // if token expired
    if (decoded.exp < (Date.now() / 1000)) {
      return authService.refreshJWTToken().concatMap((newToken) => {
        const clonedReq = req.clone({
          headers: req.headers.set('Authorization', 'JWT ' + newToken)
        });
        return next.handle(clonedReq);
      });
    }

    const clonedReq = req.clone({ headers: req.headers.append('Authorization', 'JWT ' + token) });
    return next.handle(clonedReq);
  }
intercept(req:HttpRequest,next:HttpHandler):可观察{
const authService=this.inj.get(authService);
const token=authService.getToken();
//如果没有令牌或这是刷新令牌请求
如果(!token | | req.url.split('/').pop(){
返回next.handle(req);
}
const decoded=jwt.decode(令牌);
//如果令牌过期
if(decoded.exp<(Date.now()/1000)){
返回authService.refreshJWTToken().concatMap((newToken)=>{
const clonedReq=req.clone({
headers:req.headers.set('Authorization','JWT'+newToken)
});
返回next.handle(clonedReq);
});
}
const clonedReq=req.clone({headers:req.headers.append('Authorization','JWT'+token)});
返回next.handle(clonedReq);
}
我需要的函数是authService.refreshJWTToken()


我知道这与可观测算子有关,但我对这一点有点陌生。

好的,我读了这篇文章后得到了它:

我的函数如下所示(同时处理req):

handleRefreshToken(请求:HttpRequest,下一步:HttpHandler):可观察{
const authService=this.inj.get(authService);
如果(!this.isRefreshingToken){
this.isRefreshingToken=true;
//在此处重置,以便以下请求等待令牌
//从refreshToken调用返回。
authService.tokenSubject.next(null);
返回authService.doRefreshToken()
.switchMap((newToken:string)=>{
authService.tokenSubject.next(newToken);
返回next.handle(this.addToken(req,newToken));
})
.catch(错误=>{
authService.logout();
返回可观察。抛出(错误);
})
.最后(()=>{
this.isRefreshingToken=false;
});
}否则{
返回authService.tokenSubject
.filter(令牌=>令牌!=null)
.采取(1)
.switchMap(令牌=>{
返回next.handle(this.addToken(req,token));
});
}
}
感谢瓦迪姆(瓦金)苏明的帮助

handleRefreshToken(req: HttpRequest<any>, next: HttpHandler): Observable<any> {
  const authService = this.inj.get(AuthService);

  if (!this.isRefreshingToken) {
    this.isRefreshingToken = true;

    // Reset here so that the following requests wait until the token
    // comes back from the refreshToken call.
    authService.tokenSubject.next(null);

    return authService.doRefreshToken()
      .switchMap((newToken: string) => {
        authService.tokenSubject.next(newToken);
        return next.handle(this.addToken(req, newToken));
      })
      .catch(err => {
        authService.logout();
        return Observable.throw(err);
      })
      .finally(() => {
        this.isRefreshingToken = false;
      });
  } else {
    return authService.tokenSubject
      .filter(token => token != null)
      .take(1)
      .switchMap(token => {
        return next.handle(this.addToken(req, token));
      });
  }
}