问题
I'm using JWT with refresh token strategy as authentication and I have an interceptor in my Angular client that sends the token as a header.
I check for expiration before sending, and refresh the token with my refreshToken if needed.
The problem is when sending 2 (or more) requests, both trying to refresh the token. I need a function that sends req for refresh token and when called multiple times at once, makes only 1 http req to the server for refresh and returns the new updated token to all who called it.
This is my interceptor:
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);
}
The function that I need is authService.refreshJWTToken();
I know it's something that has to do with Observables operators but I'm a bit new to this.
回答1:
Alright I got it after reading this: https://www.intertech.com/Blog/angular-4-tutorial-handling-refresh-token-with-new-httpinterceptor/
My function looks like this (also handling the req):
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));
});
}
}
Thanks to Vadim (the vagin) Siomin for the help!
来源:https://stackoverflow.com/questions/47868771/angular-refresh-token-only-once