// vim: set tw=80 ts=2 sw=2 sts=2 : import { Injectable, Injector } from '@angular/core'; import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpErrorResponse } from '@angular/common/http'; import { Observable} from 'rxjs/Rx'; import 'rxjs/add/operator/catch'; import { Logger } from '@nsalaun/ng-logger'; import { LoginService } from './login.service'; import { Token } from './token'; @Injectable() export class AuthInterceptor implements HttpInterceptor { private observable: Observable; constructor( private logger: Logger, private injector: Injector, ) {} injectAuthorizationHeader(request: HttpRequest, accessToken: string) { this.logger.log('Injecting Authorization header'); return request; } intercept( request: HttpRequest, next: HttpHandler, pass?: number ): Observable> { if(!pass) { pass = 1; } let loginService = this.injector.get(LoginService); if(request.url == loginService.url) { this.logger.log("Login URL, do not handle."); return next.handle(request); } this.logger.log(`Intercepted request, pass #${pass}`, request, next); let accessToken = loginService.accessToken; if(accessToken){ request = request.clone({ headers: request.headers.set('Authorization', `Bearer ${accessToken}`) }); } this.logger.log('Request', request); let observable: Observable = next.handle(request); return observable.catch( (error, caught): Observable => { this.logger.error("Error", error, caught); if(!(error instanceof HttpErrorResponse) || error.status != 401) { return Observable.throw(error); } this.logger.log('Unauthorized', error); if(pass === 3) { return Observable.throw(error); } if(!this.observable) { this.logger.log("No current login observable.") this.observable = loginService.login(); } return this.observable.flatMap((token: Token): Observable> => { this.logger.log("Logged in, access_token:", token.access_token); this.observable = null; return this.intercept(request, next, ++pass); }).catch((error) => { this.observable = null; return Observable.throw(error); }); } ); } }