Created
December 30, 2016 18:47
-
-
Save leon/36ac7e383331500eb20168c3347ea94a to your computer and use it in GitHub Desktop.
Angular Secure HTTP Service (JWT)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
Http, | |
ConnectionBackend, | |
Headers, | |
Request, | |
RequestOptions, | |
RequestOptionsArgs, | |
Response, | |
RequestMethod, | |
} from '@angular/http'; | |
import { Observable } from 'rxjs/Observable'; | |
import { ErrorObservable } from 'rxjs/observable/ErrorObservable'; | |
import { SecurityService } from './security.service'; | |
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 | |
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 | |
}) | |
}); | |
// securityService.accessToken returns an Observable with a JWT token | |
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<any> { | |
if (errorResponse.status === 401) { | |
console.log('redirecting to login'); | |
window.location.href = '/login'; | |
return Observable.empty(); | |
} | |
console.error(errorResponse); | |
return Observable.throw(errorResponse.text().length > 0 ? errorResponse.json() : { status: 'error' }); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment