我正在尝试在我的网络应用中实现刷新令牌概念。
在页面刷新中,我正在调用4个API,当访问令牌到期时,我正在调用后端以获取基于刷新令牌的新访问令牌。
所以在我的情况下我能够获得新的访问令牌但又无法触发4个API调用,除非我手动进行页面刷新或从服务重新加载页面。但我不想重新加载页面,并希望在不知道最终用户的情况下完成API调用。
给出一些建议或一些想法来做到这一点。
答案 0 :(得分:1)
您可以使用Angular HttpInterceptor来解决您的问题。请参阅下面的代码段。
@Injectable()
export class KgRequestInterceptorService implements HttpInterceptor {
authenticationService: MyAuthenticationService;
snackbarService: KgSnackbarService
constructor(private injector: Injector) { }
addBearerAndHeaders(req: HttpRequest<any>, token: string, overwrite?: boolean): HttpRequest<any> {
reqHeaders = reqHeaders.set("Authorization", 'Bearer ' + token);
return req.clone({ headers: reqHeaders });
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any>> {
this.authenticationService = this.authenticationService ? this.authenticationService : this.injector.get<MyAuthenticationService>(MyAuthenticationService);
return next.handle(this.addBearerAndHeaders(req, this.authenticationService.accessToken)).pipe(
catchError((error, cought) => {
if (error instanceof HttpErrorResponse) {
switch ((<HttpErrorResponse>error).status) {
case 400:
return this.handle400Error(error);
case 401:
return this.handle401Error(req, next);
case 403:
return this.handle403Error(error);
default:
return _throw(error);
}
} else {
return _throw(error);
}
})
)
}
handle401Error(req: HttpRequest<any>, next: HttpHandler) {
if (!this.isRefreshingToken) {
this.tokenSubject.next(null);
this.isRefreshingToken = true;
console.log("isRefreshingToken", this.isRefreshingToken);
// Reset here so that the following requests wait until the token
// comes back from the refreshToken call.
this.authenticationService = this.authenticationService ? this.authenticationService : this.injector.get<KgAuthenticationService>(KgAuthenticationService);
this._location = this._location ? this._location : this.injector.get<Location>(Location);
return this.authenticationService.renewToken().pipe(
switchMap((newToken: string) => {
if (newToken) {
console.log("newToken Recieved:", newToken);
this.tokenSubject.next(newToken);
this.authenticationService.storeRenewedToken(newToken);
return next.handle(this.addBearerAndHeaders(req, newToken, true));
}
// If we don't get a new token, we are in trouble so logout.
//return this.logout();
}),
catchError(error => {
// If there is an exception calling 'refreshToken', bad news so logout.
//return this.logout();
}),
finalize(() => {
this.isRefreshingToken = false;
console.log("isRefreshingToken", this.isRefreshingToken);
})
);
} else {
return this.tokenSubject.pipe(
filter(token => token != null),
take(1),
switchMap(token => {
console.log("newtoken:", token.substr(token.length - 20, token.length - 1))
return next.handle(this.addBearerAndHeaders(req, token, true));
})
)
}
}
handle400Error(error) {
if (error && error.status === 400 && error.error && error.error.error === 'invalid_grant') {
// If we get a 400 and the error message is 'invalid_grant', the token is no longer valid so logout.
return this.logoutUser();
}
return _throw(error);
}
handle403Error(error) {
if (error.status === 403) { }
return _throw(error);
}
}
有关此问题的好文章位于https://www.intertech.com/Blog/angular-4-tutorial-handling-refresh-token-with-new-httpinterceptor/
答案 1 :(得分:0)
在这种情况下,最好使用switchMap 如果你有一个Observable并且你需要从另一个请求中获取一些东西并返回一个不同的Observable,你可以使用SwitchMap: https://blog.angular-university.io/rxjs-switchmap-operator/
ngOnInit() {
this._moviesDataService.getShowtimes()
.switchMap(res => {
const id = Object.keys(res[0].showtimes)[0]; // assuming you have one element in your array and you want the first id from showtimes
return this.getMovies(id); // assuming, you have a separate method that returns the movies
})
.subscribe(res => this.results = res)
}