|
import { |
|
Http, |
|
ConnectionBackend, |
|
Headers, |
|
Request, |
|
RequestOptions, |
|
RequestOptionsArgs, |
|
Response, |
|
RequestMethod, |
|
} from '@angular/http'; |
|
import { Observable } from 'rxjs/Observable'; |
|
import { ErrorObservable } from 'rxjs/observable/ErrorObservable'; |
|
|
|
// A service that can get the logged in users jwt token as an observable |
|
import { SecurityService } from './security.service'; |
|
|
|
// A service that handles cookies (angular2-cookie) |
|
import { CookieService } from '../cookie'; |
|
|
|
/** |
|
* Custom Http client that handles conversions to json, adds CSRF token, and jwt token and redirects to signin if token is missing |
|
*/ |
|
export class SecureHttp extends Http { |
|
|
|
constructor( |
|
backend: ConnectionBackend, |
|
defaultOptions: RequestOptions, |
|
private securityService: SecurityService, |
|
private cookieService: CookieService |
|
) { |
|
super(backend, defaultOptions); |
|
} |
|
|
|
request(url: string | Request, options?: RequestOptionsArgs): Observable<any> { |
|
if (typeof url === 'string') { |
|
return this.get(url, options); // Recursion: transform url from String to Request |
|
} |
|
|
|
return this.sendRequest(url, options); |
|
} |
|
|
|
get(url: string, options?: RequestOptionsArgs): Observable<any> { |
|
return this.sendRequest({ method: RequestMethod.Get, url: url, body: '' }, options); |
|
} |
|
|
|
post(url: string, body: string, options?: RequestOptionsArgs): Observable<any> { |
|
return this.sendRequest({ method: RequestMethod.Post, url: url, body: body }, options); |
|
} |
|
|
|
put(url: string, body: string, options?: RequestOptionsArgs): Observable<any> { |
|
return this.sendRequest({ method: RequestMethod.Put, url: url, body: body }, options); |
|
} |
|
|
|
delete(url: string, options?: RequestOptionsArgs): Observable<any> { |
|
return this.sendRequest({ method: RequestMethod.Delete, url: url, body: '' }, options); |
|
} |
|
|
|
patch(url: string, body: string, options?: RequestOptionsArgs): Observable<any> { |
|
return this.sendRequest({ method: RequestMethod.Patch, url: url, body: body }, options); |
|
} |
|
|
|
head(url: string, options?: RequestOptionsArgs): Observable<any> { |
|
return this.sendRequest({ method: RequestMethod.Head, url: url, body: '' }, options); |
|
} |
|
|
|
private sendRequest(requestOptionsArgs: RequestOptionsArgs, options?: RequestOptionsArgs): Observable<any> { |
|
|
|
let requestOptions = new RequestOptions(requestOptionsArgs); |
|
|
|
// Convert body to stringified json if it's not a string already |
|
if (typeof requestOptions.body !== 'string') { |
|
requestOptions.body = JSON.stringify(requestOptions.body); |
|
} |
|
|
|
// Get xsrf token from spring security cookie |
|
// by adding .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) |
|
const csrfToken: string = this.cookieService.get('XSRF-TOKEN'); |
|
|
|
let baseOptions: RequestOptions = new RequestOptions({ |
|
headers: new Headers({ |
|
'Content-Type': 'application/json', |
|
'X-Requested-With': 'XMLHttpRequest', |
|
'X-XSRF-TOKEN': csrfToken |
|
}) |
|
}); |
|
|
|
return this.securityService.accessToken$.mergeMap(token => { |
|
|
|
// If there is a token we add it to the baseOptions |
|
if (token) { |
|
baseOptions.headers.set('Authorization', 'Bearer ' + token); |
|
} |
|
|
|
// We create a request from the passed in method, url, body and merge our base options in there |
|
let request = new Request(baseOptions.merge(requestOptions)); |
|
|
|
return super.request(request, options) |
|
.map(res => res.json()) |
|
.catch(this.errorHandler); |
|
}); |
|
} |
|
|
|
private errorHandler(errorResponse: Response): Observable<any> | ErrorObservable { |
|
if (errorResponse.status === 401) { |
|
console.log('redirecting to login'); |
|
window.location.href = '/login'; |
|
return Observable.empty(); |
|
} |
|
|
|
// If it's a serious problem we can log it to a service if we want to |
|
if (errorResponse.status === 500) { |
|
// this.errorReporter.logError(errorResponse); |
|
} |
|
|
|
console.error(errorResponse); |
|
|
|
return Observable.throw(errorResponse.text().length > 0 ? errorResponse.json() : { status: 'error' }); |
|
} |
|
} |