keycloak-uncached

Angular 2: Added an extension to the Http class to automatically

9/22/2016 11:19:45 PM

Details

diff --git a/examples/demo-template/angular2-product-app/src/main/webapp/app/app.component.ts b/examples/demo-template/angular2-product-app/src/main/webapp/app/app.component.ts
index a6955e7..e085032 100644
--- a/examples/demo-template/angular2-product-app/src/main/webapp/app/app.component.ts
+++ b/examples/demo-template/angular2-product-app/src/main/webapp/app/app.component.ts
@@ -39,27 +39,11 @@ export class AppComponent {
   }
 
   reloadData() {
-    //angular dont have http interceptor yet
+    //angular don't have http interceptor yet
 
-    this.kc.getToken()
-      .then(token => {
-        let headers = new Headers({
-          'Accept': 'application/json',
-          'Authorization': 'Bearer ' + token
-        });
-
-        let options = new RequestOptions({ headers });
-
-        this.http.get('/database/products', options)
-          .map(res => res.json())
-          .subscribe(prods => this.products = prods,
-            error => console.log(error));
-      })
-      .catch(error => console.log(error));
-  }
-
-  private handleError(error: Response) {
-    console.error(error);
-    return Observable.throw(error.json().error || 'Server error');
+    this.http.get('/database/products')
+      .map(res => res.json())
+      .subscribe(prods => this.products = prods,
+        error => console.log(error));
   }
 }
diff --git a/examples/demo-template/angular2-product-app/src/main/webapp/app/app.module.ts b/examples/demo-template/angular2-product-app/src/main/webapp/app/app.module.ts
index 6d2891f..b747489 100644
--- a/examples/demo-template/angular2-product-app/src/main/webapp/app/app.module.ts
+++ b/examples/demo-template/angular2-product-app/src/main/webapp/app/app.module.ts
@@ -1,8 +1,9 @@
 import {NgModule} from "@angular/core";
 import {BrowserModule} from "@angular/platform-browser";
-import {HttpModule} from "@angular/http";
+import {HttpModule, Http, XHRBackend, RequestOptions} from '@angular/http';
 import {KeycloakService} from "./keycloak.service";
 import {AppComponent} from "./app.component";
+import {KeycloakHttp} from "./keycloak.http";
 
 @NgModule({
   imports: [
@@ -14,6 +15,17 @@ import {AppComponent} from "./app.component";
   ],
   providers: [
     KeycloakService,
+
+    {
+      provide: Http,
+      useFactory:
+      (
+        backend: XHRBackend,
+        defaultOptions: RequestOptions,
+        keycloakService: KeycloakService
+      ) => new KeycloakHttp(backend, defaultOptions, keycloakService),
+      deps: [XHRBackend, RequestOptions, KeycloakService]
+    }
   ],
   bootstrap: [ AppComponent ]
 })
diff --git a/examples/demo-template/angular2-product-app/src/main/webapp/app/keycloak.http.ts b/examples/demo-template/angular2-product-app/src/main/webapp/app/keycloak.http.ts
new file mode 100644
index 0000000..c1ef439
--- /dev/null
+++ b/examples/demo-template/angular2-product-app/src/main/webapp/app/keycloak.http.ts
@@ -0,0 +1,110 @@
+import {Injectable} from "@angular/core";
+import {Http, Request, ConnectionBackend, RequestOptions, RequestOptionsArgs, Response} from "@angular/http";
+
+import {KeycloakService} from "./keycloak.service";
+import {Observable} from 'rxjs/Observable';
+
+/**
+ * This provides a wrapper over the ng2 Http class that insures tokens are refreshed on each request.
+ */
+@Injectable()
+export class KeycloakHttp extends Http {
+    constructor(_backend: ConnectionBackend, _defaultOptions: RequestOptions, private _keycloakService:KeycloakService) {
+        super(_backend, _defaultOptions);
+    }
+
+    private setToken(options: RequestOptionsArgs) {
+        if (options == null || KeycloakService.auth == null || KeycloakService.auth.authz == null || KeycloakService.auth.authz.token == null) {
+            console.log("Need a token, but no token is available, not setting bearer token.");
+            return;
+        }
+
+        options.headers.set('Authorization', 'Bearer ' + KeycloakService.auth.authz.token);
+    }
+
+    private configureRequest(f:Function, url:string | Request, options:RequestOptionsArgs, body?: any):Observable<Response> {
+        let tokenPromise:Promise<string> = this._keycloakService.getToken();
+        let tokenObservable:Observable<string> = Observable.fromPromise(tokenPromise);
+        let tokenUpdateObservable:Observable<any> = Observable.create((observer) => {
+            this.setToken(options);
+            observer.next();
+            observer.complete();
+        });
+        let requestObservable:Observable<Response> = Observable.create((observer) => {
+            let result;
+            if (body) {
+                result = f.apply(this, [url, body, options]);
+            } else {
+                result = f.apply(this, [url, options]);
+            }
+
+            result.subscribe((response) => {
+                observer.next(response);
+                observer.complete();
+            });
+        });
+
+        return <Observable<Response>>Observable
+            .merge(tokenObservable, tokenUpdateObservable, requestObservable)
+            .filter((response) => response instanceof Response);
+    }
+
+    /**
+     * Performs any type of http request. First argument is required, and can either be a url or
+     * a {@link Request} instance. If the first argument is a url, an optional {@link RequestOptions}
+     * object can be provided as the 2nd argument. The options object will be merged with the values
+     * of {@link BaseRequestOptions} before performing the request.
+     */
+    request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
+        return this.configureRequest(super.request, url, options);
+    }
+
+    /**
+     * Performs a request with `get` http method.
+     */
+    get(url: string, options?: RequestOptionsArgs): Observable<Response> {
+        return this.configureRequest(super.get, url, options);
+    }
+
+    /**
+     * Performs a request with `post` http method.
+     */
+    post(url: string, body: any, options?: RequestOptionsArgs): Observable<Response> {
+        return this.configureRequest(super.post, url, options, body);
+    }
+
+    /**
+     * Performs a request with `put` http method.
+     */
+    put(url: string, body: any, options?: RequestOptionsArgs): Observable<Response> {
+        return this.configureRequest(super.put, url, options, body);
+    }
+
+    /**
+     * Performs a request with `delete` http method.
+     */
+    delete(url: string, options?: RequestOptionsArgs): Observable<Response> {
+        return this.configureRequest(super.delete, url, options);
+    }
+
+    /**
+     * Performs a request with `patch` http method.
+     */
+    patch(url: string, body: any, options?: RequestOptionsArgs): Observable<Response> {
+        return this.configureRequest(super.patch, url, options, body);
+    }
+
+    /**
+     * Performs a request with `head` http method.
+     */
+    head(url: string, options?: RequestOptionsArgs): Observable<Response> {
+        return this.configureRequest(super.head, url, options);
+    }
+
+    /**
+     * Performs a request with `options` http method.
+     */
+    options(url: string, options?: RequestOptionsArgs): Observable<Response> {
+        return this.configureRequest(super.options, url, options);
+    }
+}
\ No newline at end of file