我正在尝试在Angular 6中创建一个拦截器,以处理基于刷新令牌的新访问令牌的生成。问题是,这是基于Observables的,当我尝试发出POST请求以获取新的访问令牌时,observables的链已损坏。这是下面的组件代码:
import { HttpHandler, HttpInterceptor, HttpRequest, HttpErrorResponse, HttpResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { UserService } from './user.service';
import { BehaviorSubject, Subscription } from '../../../../node_modules/rxjs';
import { CommonFunctions } from '../../common/components/common.component';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/take';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/delay';
import 'rxjs/add/observable/of';
import { of } from 'rxjs';
import { AccountService } from './account.service';
import { ConfigurationService } from './configuration.service';
@Injectable()
export class AuthInterceptorService implements HttpInterceptor {
isRefreshingToken: boolean;
tokenSubject: BehaviorSubject<string> = new BehaviorSubject<string>(null);
currentToken: string;
refreshToken: string;
authTokenNew: string;
getNewTokenSubscription: Subscription;
constructor(private user: UserService, private common: CommonFunctions,
private ws: AccountService, private config: ConfigurationService) {
this.isRefreshingToken = false;
this.currentToken = this.user.accessToken;
this.refreshToken = this.user.refreshToken;
this.authTokenNew = '';
this.getNewTokenSubscription = null;
}
addToken(req: HttpRequest<any>, token: string): HttpRequest<any> {
return req.clone({ setHeaders: { Authorization: 'Bearer ' + token } });
}
refreshTheToken(): Observable<string> {
const payload = new URLSearchParams();
payload.append('client_id', this.config.CLIENT_ID);
payload.append('grant_type', this.config.REFRESH_TOKEN_GRANT_TYPE);
payload.append('refresh_token', this.refreshToken);
this.getNewTokenSubscription = this.ws.doLogIn(payload)
.finally(() => {
this.cleanupGetNewTokenSubscription();
})
.subscribe(
(imResponse: HttpResponse<object>) => {
this.authTokenNew = imResponse['access_token'];
this.user.refreshToken = imResponse['refresh_token'];
},
(error: HttpErrorResponse) => {
}
);
this.user.accessToken = this.authTokenNew;
return of(this.authTokenNew).delay(200);
}
cleanupGetNewTokenSubscription() {
if (this.getNewTokenSubscription) {
this.getNewTokenSubscription.unsubscribe();
this.getNewTokenSubscription = null;
}
}
getMainAuthToken() {
return this.user.accessToken;
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<any> {
if (this.getMainAuthToken()) {
return next.handle(this.addToken(req, this.getMainAuthToken()))
.catch(error => {
if (error instanceof HttpErrorResponse) {
switch ((<HttpErrorResponse>error).status) {
case 400:
return this.handle400Error(error);
case 401:
return this.handle401Error(req, next);
}
} else {
return Observable.throw(error);
}
});
} else {
return next.handle(req);
}
}
handle401Error(req: HttpRequest<any>, next: HttpHandler) {
if (!this.isRefreshingToken) {
this.isRefreshingToken = true;
this.tokenSubject.next(null);
return this.refreshTheToken()
.switchMap((newToken: string) => {
if (newToken) {
this.tokenSubject.next(newToken);
return next.handle(this.addToken(req, newToken));
}
return this.logoutUser();
})
.catch(error => {
return this.logoutUser();
})
.finally(() => {
this.isRefreshingToken = false;
});
} else {
return this.tokenSubject
.filter(token => token != null)
.take(1)
.switchMap(token => {
return next.handle(this.addToken(req, token));
});
}
}
handle400Error(error) {
if (error && error.status === 400 && error.error && error.error.error === 'invalid_grant') {
return this.logoutUser();
}
return Observable.throw(error);
}
logoutUser() {
this.common.logOut();
return Observable.throw('');
}
}
问题出在refreshTheToken()方法中。在该调用完成之前,正在访问新令牌的值。有什么线索可以解决吗?
谢谢!