Angular 在发出克隆请求之前续订令牌

Angular 在发出克隆请求之前续订令牌,angular,typescript,jwt,jwt-auth,refresh-token,Angular,Typescript,Jwt,Jwt Auth,Refresh Token,因此,如果令牌使用刷新令牌过期,我想续订访问令牌,这就是我的令牌拦截器的外观: intercept(req: HttpRequest<any>, next: HttpHandler) { let authservice = this.injector.get(AuthService) let tokenreq = req.clone({ setHeaders: { Authorization: `Bearer ${authser

因此,如果令牌使用刷新令牌过期,我想续订访问令牌,这就是我的令牌拦截器的外观:

intercept(req: HttpRequest<any>, next: HttpHandler) {
    let authservice = this.injector.get(AuthService)
      let tokenreq = req.clone({
        setHeaders: {
          Authorization: `Bearer ${authservice.setToken()}`
        }
      })
      return next.handle(tokenreq).pipe(
        catchError((error) => {
          if (error.error.message == 'The incoming token has expired') {
            authservice.renewToken()
            let tokenreq = req.clone({
              setHeaders: {
                Authorization: `Bearer ${authservice.setToken()}`
              }
            })
            return next.handle(tokenreq)
          }
          else return throwError(error)
        })
      );
    }
  }
intercept(请求:HttpRequest,下一步:HttpHandler){
让authservice=this.injector.get(authservice)
让tokenreq=req.clone({
集合标题:{
授权:`Bearer${authservice.setToken()}`
}
})
返回next.handle(tokenreq).pipe(
catchError((错误)=>{
if(error.error.message=='传入令牌已过期'){
authservice.RenewatToken()
让tokenreq=req.clone({
集合标题:{
授权:`Bearer${authservice.setToken()}`
}
})
返回next.handle(tokenreq)
}
else返回投掷器(错误)
})
);
}
}
问题是在我收到过期的令牌消息后,
authservice.renewToken()
authservice.setToken()
同时被调用,因此再次设置过期的令牌


另一个问题是,如果用户在cookie中再次打开应用程序并使用过期的令牌,那么所有的
GET
方法都将抛出错误并多次请求新令牌。如何处理过期令牌错误?

您可以通过使用
retryWhen
运算符将
setToken
连接到返回的可观察对象来修复此故障行为。 这样,
renewToken
setToken
将不会并行执行,更重要的是,
setToken
将由拦截器链在每个请求中考虑

intercept(req: HttpRequest<any>, next: HttpHandler) {
    const authservice = this.injector.get(AuthService);
      
    return of(req).pipe(
          switchMap((req) => {
            return authservice.setToken()               // Gets the token. *should rename this method to getToken()
                .pipe(
                    map(token => {                      // Set the token.
                        const tokenreq = req.clone({
                            setHeaders: {
                                Authorization: `Bearer ${authservice.setToken()}`
                            }
                            });

                        return tokenreq;
                    })
                ),
            switchMap(tokenreq => next.handle(tokenreq)), // Execute next interceptor and eventually send the request.
            retryWhen(errors => errors.pipe(
                mergeMap((err: HttpErrorResponse, i: number) => {
                    authservice.invalidateToken()        // Invalidate token. Erase token or expires it.
                    if (error.error.message == 'The incoming token has expired') {
                        return of(err);                   // will start the current pipe all over again - and get the token once again.
                    }

                    return throwError(error);
                })
            )
        )
  }
在这个回答中:

1) interceptor method execution -> setToken() -> return observable
2) request asked by http.get(..) -> chain of observables return by interceptors and setToken() inside one! -> request sent -> chain of observables
注意:

setToken
方法应返回一个带有该标记的可观察对象,并且
invalidateToken
应能够删除该标记

这可以通过以下方式轻松实现:

private token$: AsyncSubject<string>;

getToken(): Observable {
    if (!token$) this.token$ = new AsyncSubject();

    getTokenOperation.subscribe(t => {
        this.token$.next(t);
        this.token$.complete();
    })

    return this.token$.asObservable();
}

invalidateToken() {
    this.token$ = null;
}
private-token$:AsyncSubject;
getToken():可观察{
如果(!token$)此.token$=新的AsyncSubject();
getTokenOperation.subscribe(t=>{
此.token$.next(t);
此.token$.complete();
})
返回此.token$.asObservable();
}
失效{
this.token$=null;
}

您需要传递新令牌

return next.handle(request).pipe(
        map((event: HttpEvent<any>) => {
            return this.eventCallSendBack(event);
        }),
        catchError((error: HttpErrorResponse) => {
            if (error instanceof HttpErrorResponse) {
                switch (error.status) {
                    case 401:
                        return this.handle401Error(request, next);
                    case 403:
                        //DO Want you want here.
                        throw error;
                    default:
                        throw error;
                }
            }
            throw error;
        })
    );
您希望拥有和添加令牌fn:

private addToken(event: HttpRequest<any>, token: string) {
    return event.clone({
        setHeaders: {
            Authorization: `Bearer ${token}`
        }
    });
}
private addToken(事件:HttpRequest,token:string){
return event.clone({
集合标题:{
授权:`Bearer${token}`
}
});
}
现在假设您的令牌已过期,您需要创建fn,它将从某个身份验证中获取新令牌

private handle401Error(
    request: HttpRequest<any>,
    next: HttpHandler
): Observable<any> {
        return authServices
            .refreshToken(
                token //This is the old token to get the new.
            )
            .pipe(
                map(jwt => {
                    return jwt;
                }),
                switchMap((jwt: any) => {
                    return next
                        .handle(this.addToken(request, jwt.token)) // Add token in responce 
                        .pipe(
                            map((event: HttpEvent<any>) => {
                                return this.eventCallSendBack(event);
                            })
                        );
                }),
                catchError(err => {
                    return throwError(err);
                })
            );
    
}
private handle401错误(
请求:HttpRequest,
下一步:HttpHandler
):可见{
返回授权服务
.refreshToken(
令牌//这是获取新令牌的旧令牌。
)
.烟斗(
映射(jwt=>{
返回jwt;
}),
switchMap((jwt:any)=>{
下一个返回
.handle(this.addToken(request,jwt.token))//在response中添加令牌
.烟斗(
映射((事件:HttpEvent)=>{
返回此.eventCallSendBack(事件);
})
);
}),
catchError(err=>{
回程抛掷器(err);
})
);
}

Renewtoken和settoken是同步方法,对吗?我想是的。我还没有宣布它们是异步的。你能展示一下
RenewatToken
的代码吗?你能使用吗?RenewatToken方法的具体功能是什么?
private addToken(event: HttpRequest<any>, token: string) {
    return event.clone({
        setHeaders: {
            Authorization: `Bearer ${token}`
        }
    });
}
private handle401Error(
    request: HttpRequest<any>,
    next: HttpHandler
): Observable<any> {
        return authServices
            .refreshToken(
                token //This is the old token to get the new.
            )
            .pipe(
                map(jwt => {
                    return jwt;
                }),
                switchMap((jwt: any) => {
                    return next
                        .handle(this.addToken(request, jwt.token)) // Add token in responce 
                        .pipe(
                            map((event: HttpEvent<any>) => {
                                return this.eventCallSendBack(event);
                            })
                        );
                }),
                catchError(err => {
                    return throwError(err);
                })
            );
    
}