Jul*_*rra 0 http interceptor angular-http-interceptors angular
我正在使用Http
Angular HttpClient
的解决方案,但是我决定进行迁移并使用新的解决方案,并且我试图创建一种解决方案Interceptors
来管理需要刷新令牌以及需要将标头修改为放置授权令牌。
首先,我找到了这些文章以及其他许多文章:
...但是如果您只想处理放置授权标头的操作,那么这些解决方案是完美的。然后我想出了这个解决方案
@Injectable()
export class RefreshTokenInterceptor implements HttpInterceptor {
constructor(private injector: Injector, private authService: Auth) {
}
private getRequestWithAuthentication(request: HttpRequest<any>, next: HttpHandler, auth: OAuthService): Observable<HttpEvent<any>> {
const req = request.clone({
headers: request.headers.set('Authorization', auth.getHeaderAuthorization())
});
return next.handle(req);
}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// To avoid cyclic dependency
const auth = this.injector.get(OAuthService);
if (auth.hasAuthorization()) {
return this.getRequestWithAuthentication(request, next, auth);
} else if (auth.hasAuthorizationRefresh() && request.url !== AUTHORIZE_URL) {
return auth.refreshToken().flatMap(
(res: any) => {
auth.saveTokens(res);
return this.getRequestWithAuthentication(request, next, auth);
}
).catch(() => {
return next.handle(request);
});
} else if (request.url === AUTHORIZE_URL) {
return next.handle(request);
}
return this.getRequestWithAuthentication(request, next, auth);
}
}
Run Code Online (Sandbox Code Playgroud)
这样做的主要思想很简单:
HttpClient
在OAuthService
这样它会自拦截传球也和它的会是一个无限循环,如果我不签。在某些情况下,此解决方案可以正常工作,但是事情是,例如,当令牌过期并且您有多个请求时,每个请求都将尝试刷新令牌。
在此之后,我找到了这个解决方案,但我想知道您如何看待代码和执行方式。
好的,首先,我创建了一个服务来保存刷新令牌请求的状态,并且可以观察到该请求何时完成。
@Injectable()
export class RefreshTokenService {
public processing: boolean = false;
public storage: Subject<any> = new Subject<any>();
public publish(value: any) {
this.storage.next(value);
}
}
Run Code Online (Sandbox Code Playgroud)
我注意到最好有两个拦截器,一个拦截器刷新令牌并处理令牌,另一个拦截器放置授权头(如果存在)。
@Injectable()
export class RefreshTokenInterceptor implements HttpInterceptor {
constructor(private injector: Injector, private tokenService: RefreshTokenService) {
}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const auth = this.injector.get(OAuthService);
if (!auth.hasAuthorization() && auth.hasAuthorizationRefresh() && !this.tokenService.processing && request.url !== AUTHORIZE_URL) {
this.tokenService.processing = true;
return auth.refreshToken().flatMap(
(res: any) => {
auth.saveTokens(res);
this.tokenService.publish(res);
this.tokenService.processing = false;
return next.handle(request);
}
).catch(() => {
this.tokenService.publish({});
this.tokenService.processing = false;
return next.handle(request);
});
} else if (request.url === AUTHORIZE_URL) {
return next.handle(request);
}
if (this.tokenService.processing) {
return this.tokenService.storage.flatMap(
() => {
return next.handle(request);
}
);
} else {
return next.handle(request);
}
}
}
Run Code Online (Sandbox Code Playgroud)
因此,在这里,我等待刷新令牌可用或失败,然后释放需要授权标头的请求。
@Injectable()
export class TokenInterceptor implements HttpInterceptor {
constructor(private injector: Injector) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const auth = this.injector.get(OAuthService);
let req = request;
if (auth.hasAuthorization()) {
req = request.clone({
headers: request.headers.set('Authorization', auth.getHeaderAuthorization())
});
}
return next.handle(req).do(
() => {},
(error: any) => {
if (error instanceof HttpErrorResponse) {
if (error.status === 401) {
auth.logOut();
}
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
@NgModule({
imports: [
...,
HttpClientModule
],
declarations: [
...
],
providers: [
...
OAuthService,
AuthService,
RefreshTokenService,
{
provide: HTTP_INTERCEPTORS,
useClass: RefreshTokenInterceptor,
multi: true
},
{
provide: HTTP_INTERCEPTORS,
useClass: TokenInterceptor,
multi: true
}
],
bootstrap: [AppComponent]
})
export class AppModule {
}
Run Code Online (Sandbox Code Playgroud)
请提供任何反馈意见,如果我做错了什么,请告诉我。我正在使用Angular 4.4.6进行测试,但是我不知道它是否可以在Angular 5上正常工作。