[英]Angular 7: JWT expiration time check error
我正在创建一个角度应用程序。 目前我想检查 JWT 的过期时间。 我想在每次 API 调用之前检查 JWT exp 时间。 前任:
但我收到一个错误。
未捕获(承诺):类型错误:您在需要流的地方提供了“未定义”。 您可以提供 Observable、Promise、Array 或 Iterable。
我认为它们是 async/await 函数的错误,但我无法解决这个问题。
import {Inject, Injectable} from '@angular/core';
import {
HttpClient,
HttpErrorResponse,
HttpEvent,
HttpHandler,
HttpInterceptor,
HttpRequest,
HttpResponse
} from '@angular/common/http';
import {Observable} from 'rxjs';
import {catchError, tap} from 'rxjs/operators';
import {SHttpConfig} from './http.conf';
import {StorageService} from '../../services/storage.service';
import {PopAlertService} from '../pop-alert/pop-alert.service';
import {Router} from '@angular/router';
import {JwtService} from '../../services/jwt.service';
import {getDecodedJWT} from '../../helpers/functions';
@Injectable()
export class SHttpInjectorService implements HttpInterceptor {
cachedRequests: Array<HttpRequest<any>> = [];
constructor(
private storage: StorageService,
private config: SHttpConfig,
private pop: PopAlertService,
private router: Router,
private jwt: JwtService
) {
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const user: any = this.storage.user;
const addToken = !req.urlWithParams.includes('token');
const token = user ? user.token : null;
if (token && !req.url.includes('token=') && addToken) {
this.modify(req, user, token).then(res => {
req = res;
return this.handleRequest(next, req, token);
});
} else {
return this.handleRequest(next, req, token);
}
}
private async modify(req, user, token) {
let user_token = user.token;
const expireDate = getDecodedJWT(token).exp;
if (Date.now() >= expireDate * 1000) {
const result = await this.jwt.getRefreshedJWT().toPromise();
user_token = result.token;
user.token = user_token;
this.storage.user = user;
}
return req.clone({
setHeaders: {Authorization: `Bearer ${user_token}`},
setParams: {token: user_token}
});
}
private handleRequest(next, req, token) {
return next.handle(req).pipe(tap((event: HttpEvent<any>) => {
if (event instanceof HttpResponse) {
if (event.body.code === 401 && token) {
this.router.navigate(['/']).catch(err => {console.log(err); });
this.storage.removeData();
this.pop.open('Your Session has expired ');
}
}
}, (err: any) => {
if (err instanceof HttpErrorResponse) {
if (err.status === 401) {
this.collectFailedRequest(req);
} else if (err.status === 0 && err.message.match('Http failure response')) {
this.pop.open('Couldn\'t get response from server');
}
} else {
// tslint:disable-next-line:no-shadowed-variable
this.router.navigate(['/']).catch(err => {console.log(err); });
}
}));
}
public collectFailedRequest(request): void {
this.cachedRequests.push(request);
}
}
正如错误所说的是期待一个流而不是未定义,问题的原因在 if 子句中:
if (token && !req.url.includes('token=') && addToken) {
this.modify(req, user, token).then(res => { // <-- here
req = res;
return this.handleRequest(next, req, token);
});
}
方法拦截期望返回一个Observable并且当满足 if 条件时它不会返回任何内容,因为您将 return 语句放在异步方法中,因此编译器将回调函数放入回调队列并继续执行下一行,因为没有任何东西它返回未定义。
我建议使用 Observables 和 RXJS 运算符并执行以下操作:
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const user: any = this.storage.user;
const addToken = !req.urlWithParams.includes('token');
const token = user ? user.token : null;
if (token && !req.url.includes('token=') && addToken) {
return this.modify(req, next, user, token);
} else {
return this.handleRequest(next, req, token);
}
}
private modify(req, next, user, token): Observable<HttpEvent<any>> {
let user_token = user.token;
const expireDate = getDecodedJWT(token).exp;
if (Date.now() >= expireDate * 1000) {
return this.jwt.getRefreshedJWT().pipe(flatMap((result) => {
user_token = result.token;
user.token = user_token;
this.storage.user = user;
const clonedReq = req.clone({
setHeaders: {Authorization: `Bearer ${user_token}`},
setParams: {token: user_token}
});
return this.handleRequest(next, clonedReq, token);
}));
}
return this.handleRequest(next, req, token);
}
此外,我认为如果您以不同的方式处理这个问题会更好,因为使用这种方法您正在检查令牌是否在每个请求中过期,这会在对服务器的所有请求中增加一些额外的延迟,使请求最后如果令牌已过期,您可以采用更懒惰的方法并从服务器返回错误,然后您可以存储请求,触发刷新令牌逻辑并最终恢复失败的请求。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.