我正在使用 ionic 3、Angular 5 和 rxjs 5。 我在我的应用程序中创建了拦截器,并且可以很好地拦截所有传出 API,并向 header 添加 token ,并在原始 token 过期时刷新 token 。
import {Observable, BehaviorSubject} from 'rxjs';
import {_throw} from "rxjs/observable/throw";
import {take, filter, catchError, switchMap, finalize} from 'rxjs/operators';
import {Injectable, Injector} from "@angular/core";
import {HttpInterceptor, HttpRequest, HttpHandler, HttpSentEvent, HttpHeaderResponse, HttpProgressEvent,
HttpResponse, HttpUserEvent, HttpErrorResponse} from "@angular/common/http";
import {ResetApiProvider} from "../providers/reset-api/reset-api";
import {Events} from "ionic-angular";
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
isRefreshingToken: boolean = false;
tokenSubject: BehaviorSubject<string> = new BehaviorSubject<string>(null);
constructor(private injector: Injector, public event: Events) {}
addToken(req: HttpRequest<any>, token: string): HttpRequest<any> {
return req.clone({setHeaders: {Authorization: 'Bearer ' + token}})
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any>> {
const authService = this.injector.get(ResetApiProvider);
return next.handle(this.addToken(req, authService.getAuthToken())).pipe(
catchError(error => {
if (error instanceof HttpErrorResponse) {
switch ((<HttpErrorResponse>error).status) {
case 400:
return this.handle400Error(error);
case 401:
return this.handle401Error(req, next);
default:
return _throw(error);
}
} else {
return _throw(error);
}
}));
}
//maybe use later for blacklist tokens
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);
}
handle401Error(req: HttpRequest<any>, next: HttpHandler) {
if (!this.isRefreshingToken) {
this.isRefreshingToken = true;
// Reset here so that the following requests wait until the token
// comes back from the refreshToken call.
this.tokenSubject.next(null);
const authService = this.injector.get(ResetApiProvider);
return authService.refreshToken().pipe(
switchMap((newToken: string) => {
console.log('bbbbbbb');
if (newToken) {
this.tokenSubject.next(newToken);
return next.handle(this.addToken(req, newToken));
}
console.log('qqqq');
// If we don't get a new token, we are in trouble so logout.
return this.logoutUser();
}),
catchError(error => {
// If there is an exception calling 'refreshToken', bad news so logout.
return this.logoutUser();
}),
finalize(() => {
this.isRefreshingToken = false;
}),);
} else {
return this.tokenSubject.pipe(
filter(token => token != null),
take(1),
switchMap(token => {
return next.handle(this.addToken(req, token));
}),);
}
}
logoutUser() {
const authService = this.injector.get(ResetApiProvider);
authService.logout();
this.event.publish('UNAUTHORIZED');
return _throw("please login");
}
}
我的刷新 token 功能:
public refreshToken(): Observable<string> {
const url = `${apiUrl}/auth/refresh`;
console.log('fffff');
return this.http.post(url, {token: this.getAuthToken()},httpOptions)
.pipe(
map((res) => {
let token: any = res;
this.storage.set('token', token.data);
console.log(token.data);
this.currentToken = token.data;
return token.data;
catchError(this.handleError)
);
}
除非,如果refreshToken()失败,则在AuthInterceptor类中永远不会到达catch()和finally()!如何解决这个问题!? 所以我无法清除存储并导航到登录页面。
最佳答案
尝试这个调整。
public refreshToken(): Observable<string> {
const url = `${apiUrl}/auth/refresh`;
console.log('fffff');
return this.http.post(url, {token: this.getAuthToken()},httpOptions)
.pipe(
map((res) => {
let token: any = res;
this.storage.set('token', token.data);
console.log(token.data);
this.currentToken = token.data;
//return token.data;
}),
catchError(this.handleError)
);
}
- 即return 和 catchError 之间缺少的
}),
。 - return 似乎也是多余的,所以我注释掉了。
每here .
请告诉我这是否有帮助。
关于javascript - 刷新 token 拦截器 ionic 时捕获错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54929047/