我需要对403 Forbidden HTTP状态(获取/刷新)JWT令牌做出反应(在拦截器类中)并使用新令牌重试请求。
在下面的代码中,当服务器返回错误响应时,它会转到成功回调(而不是我期望的错误回调),并且事件是typeof对象(对错误响应没有反应)。事件对象如下所示: {类型:0}。
问题:
- 如何正确处理httpErrorResponse(403 Forbidden)in HttpInterceptor当我需要刷新accessToken并重试http请求时?
import {
HttpInterceptor,
HttpRequest,
HttpResponse,
HttpHandler,
HttpEvent
} from '@angular/common/http';
import 'rxjs/add/operator/map';
@Injectable()
class JWTInterceptor implements HttpInterceptor {
constructor(private tokenService: TokenService) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
let myHeaders = req.headers;
if (this.tokenService.accessToken) {
myHeaders = myHeaders.append('Authorization',`${this.tokenService.accessToken.token_type} ${this.tokenService.accessToken.access_token}`)
}
const authReq = req.clone({headers: myHeaders});
return next.handle(authReq).map((event: HttpEvent<any>) => {
if (event instanceof HttpResponse) {
// success callback
}
}, (err: any) => {
if (err instanceof HttpErrorResponse {
if (err.status === 403) {
// error callback
this.tokenService.obtainAccessToken()
}
}
})
.retry(1);
}
}
答案 0 :(得分:8)
我对这个问题的最终解决方案:
@Injectable()
export class WebApiInterceptor implements HttpInterceptor {
constructor(private tokenService: TokenService) {
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
console.log('*An intercepted httpRequest*', req, this.tokenService.accessToken);
const authReq = this.authenticateRequest(req);
console.log('*Updated httpRequest*', authReq);
return next.handle(authReq)
.map((event: HttpEvent<any>) => {
if (event instanceof HttpResponse) {
console.log('*An intercepted httpResponse*', event);
return event;
}
})
.catch((error: any) => {
if (error instanceof HttpErrorResponse) {
if (error.status === 403 && error.url !== environment.authEndpoint) {
return this.tokenService
.obtainAccessToken()
.flatMap((token) => {
const authReqRepeat = this.authenticateRequest(req);
console.log('*Repeating httpRequest*', authReqRepeat);
return next.handle(authReqRepeat);
});
}
} else {
return Observable.throw(error);
}
})
}
}
功能
authenticateRequest(req)
只需将Authorization标头添加到原始请求的副本
功能
obtainAccessToken()
获取新的令牌表格授权服务器并存储
答案 1 :(得分:4)
您需要从RxJS添加catch
运算符。这是一个错误,你可以相应地处理它。
当您收到状态为0的错误时,这很可能意味着远程服务器已关闭且无法建立连接。
看看我的示例逻辑:
this.http.request(url, options)
.map((res: Response) => res.json())
.catch((error: any) => {
const err = error.json();
// Refresh JWT
if (err.status === 403) {
// Add your token refresh logic here.
}
return Observable.throw(err);
});
为了使刷新逻辑通过拦截器,您需要返回调用,函数也应该返回Observable
。例如,修改上面的原始逻辑:
this.http.request(url, options)
.map((res: Response) => res.json())
.catch((error: any) => {
const err = error.json();
// Refresh JWT
if (err.status === 403) {
// refreshToken makes another HTTP call and returns an Observable.
return this.refreshToken(...);
}
return Observable.throw(err);
});
如果您希望能够重试原始请求,您可以执行的操作是传递原始请求数据,以便在成功刷新令牌后,您可以再次进行呼叫。例如,这就是refreshToken
函数的外观:
refreshToken(url: stirng, options: RequestOptionsArgs, body: any, tokenData: any): Observable<any>
return this.post(`${this.url}/token/refresh`, tokenData)
.flatMap((res: any) => {
// This is where I retry the original request
return this.request(url, options, body);
});
}
答案 2 :(得分:3)
只想分享对我有用的东西:
@Injectable()
export class AutoReLoginInterceptor implements HttpInterceptor {
constructor() {
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// as we want to intercept the possible errors, instead of directly returning the request execution, we return an Observable to control EVERYTHING
return new Observable<HttpEvent<any>>(subscriber => {
// first try for the request
next.handle(req)
.subscribe((event: HttpEvent<any>) => {
if (event instanceof HttpResponse) {
// the request went well and we have valid response
// give response to user and complete the subscription
subscriber.next(event);
subscriber.complete();
}
},
error => {
if (error instanceof HttpErrorResponse && error.status === 401) {
console.log('401 error, trying to re-login');
// try to re-log the user
this.reLogin().subscribe(authToken => {
// re-login successful -> create new headers with the new auth token
let newRequest = req.clone({
headers: req.headers.set('Authorization', authToken)
});
// retry the request with the new token
next.handle(newRequest)
.subscribe(newEvent => {
if (newEvent instanceof HttpResponse) {
// the second try went well and we have valid response
// give response to user and complete the subscription
subscriber.next(newEvent);
subscriber.complete();
}
}, error => {
// second try went wrong -> throw error to subscriber
subscriber.error(error);
});
});
} else {
// the error was not related to auth token -> throw error to subscriber
subscriber.error(error);
}
});
});
}
/**
* Try to re-login the user.
*/
private reLogin(): Observable<string> {
// obtain new authorization token and return it
}
}
答案 3 :(得分:0)
import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable()
export class JwtInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// add authorization header with jwt token if available
const currentUser = JSON.parse(sessionStorage.getItem('currentUser'));
console.log('Interceter called');
console.log(currentUser);
// const re = 'https://newsapi.org';
const re = '/user';
if (request.url.search(re) === -1) {
if (currentUser && currentUser.token) {
console.log('Token is being added....!!!!!');
// console.log(currentUser.token);
request = request.clone({
setHeaders: {
Authorisation: `Token ${currentUser.token}`,
}
});
}
console.log('Request Sent :');
console.log(request);
}
return next.handle(request);
}
}