1. Overview
In this quick tutorial, we’re going to upgrade our existing Angular application described here, to use Angular 4 instead of AngularJS.
2. Setup Angular4
First, we’ll use Angular CLI to generate and manage our front-end modules.
First, we’ll install node and npm – as Angular CLI is an npm tool.
Then, Include Maven dependencies we need to use frontend-maven-plugin to build our Angular project using maven:
<build> <plugins> <plugin> <groupId>com.github.eirslett</groupId> <artifactId>frontend-maven-plugin</artifactId> <version>1.3</version> <configuration> <nodeVersion>v6.10.2</nodeVersion> <npmVersion>3.10.10</npmVersion> <workingDirectory>src/main/resources</workingDirectory> </configuration> <executions> <execution> <id>install node and npm</id> <goals> <goal>install-node-and-npm</goal> </goals> </execution> <execution> <id>npm install</id> <goals> <goal>npm</goal> </goals> </execution> <execution> <id>npm run build</id> <goals> <goal>npm</goal> </goals> <configuration> <arguments>run build</arguments> </configuration> </execution> </executions> </plugin> </plugins> </build>
And finally, generate new Module using Angular CLI:
ng new oauthApp
Note that we’ll have two front-end modules – one for password flow and the other for implicit flow.
In the following sections, we will discuss the Angular app logic for each module.
3. Password Flow using Angular4
Next, let’s discuss the logic of our Password Flow front end module.
3.1. App Service
Let’s start with our AppService – located at app.service.ts – which contains the logic for server interactions:
- obtainAccessToken(): to obtain Access token given user credentials
- saveToken(): to save our access token in a cookie using ng2-cookies library
- getResource(): to get a Foo object from server using its ID
- checkCredentials(): to check if user is logged in or not
- logout(): to delete access token cookie and log user out
export class Foo { constructor( public id: number, public name: string) { } } @Injectable() export class AppService { constructor( private _router: Router, private _http: Http){} obtainAccessToken(loginData){ let params = new URLSearchParams(); params.append('username',loginData.username); params.append('password',loginData.password); params.append('grant_type','password'); params.append('client_id','fooClientIdPassword'); let headers = new Headers({'Content-type': 'application/x-www-form-urlencoded; charset=utf-8', 'Authorization': 'Basic '+btoa("fooClientIdPassword:secret")}); let options = new RequestOptions({ headers: headers }); this._http.post('http://localhost:8081/spring-security-oauth-server/oauth/token', params.toString(), options) .map(res => res.json()) .subscribe( data => this.saveToken(data), err => alert('Invalid Credentials')); } saveToken(token){ var expireDate = new Date().getTime() + (1000 * token.expires_in); Cookie.set("access_token", token.access_token, expireDate); this._router.navigate(['/']); } getResource(resourceUrl) : Observable<Foo>{ var headers = new Headers({'Content-type': 'application/x-www-form-urlencoded; charset=utf-8', 'Authorization': 'Bearer '+Cookie.get('access_token')}); var options = new RequestOptions({ headers: headers }); return this._http.get(resourceUrl, options) .map((res:Response) => res.json()) .catch((error:any) => Observable.throw(error.json().error || 'Server error')); } checkCredentials(){ if (!Cookie.check('access_token')){ this._router.navigate(['/login']); } } logout() { Cookie.delete('access_token'); this._router.navigate(['/login']); } }
3.2. Login Component
Next, let’s take a look at our LoginComponent which is responsible for the login form:
@Component({ selector: 'login-form', providers: [AppService], template: `<h1>Login</h1> <input type="text" [(ngModel)]="loginData.username" /> <input type="password" [(ngModel)]="loginData.password"/> <button (click)="login()" type="submit">Login</button>` }) export class LoginComponent { public loginData = {username: "", password: ""}; constructor(private _service:AppService) {} login() { this._service.obtainAccessToken(this.loginData); } }
3.3. Home Component
Next, our HomeComponent which is responsible for displaying and manipulating our Home Page:
@Component({ selector: 'home-header', providers: [AppService], template: `<span>Welcome !!</span> <a (click)="logout()" href="#">Logout</a> <foo-details></foo-details>` }) export class HomeComponent { constructor( private _service:AppService){} ngOnInit(){ this._service.checkCredentials(); } logout() { this._service.logout(); } }
3.4. Foo Component
Finally, our FooComponent to display our Foo details:
@Component({ selector: 'foo-details', providers: [AppService], template: `<h1>Foo Details</h1> <label>ID</label> <span>{{foo.id}}</span> <label>Name</label> <span>{{foo.name}}</span> <button (click)="getFoo()" type="submit">New Foo</button>` }) export class FooComponent { public foo = new Foo(1,'sample foo'); private foosUrl = 'http://localhost:8082/spring-security-oauth-resource/foos/'; constructor(private _service:AppService) {} getFoo(){ this._service.getResource(this.foosUrl+this.foo.id) .subscribe( data => this.foo = data, error => this.foo.name = 'Error'); } }
3.5. App Component
Our simple AppComponent to act as the root component:
@Component({ selector: 'app-root', template: `<router-outlet></router-outlet>` }) export class AppComponent {}
And the AppModule where we wrap all our components, services and routes:
@NgModule({ declarations: [ AppComponent, HomeComponent, LoginComponent, FooComponent ], imports: [ BrowserModule, FormsModule, HttpModule, RouterModule.forRoot([ { path: '', component: HomeComponent }, { path: 'login', component: LoginComponent }]) ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
4. Implicit Flow
Next, we’ll focus on the Implicit Flow module.
4.1. App Service
Similarly, we will start with our service, but this time we will use library angular-oauth2-oidc instead of obtaining access token ourselves:
@Injectable() export class AppService { constructor( private _router: Router, private _http: Http, private oauthService: OAuthService){ this.oauthService.loginUrl = 'http://localhost:8081/spring-security-oauth-server/oauth/authorize'; this.oauthService.redirectUri = 'http://localhost:8086/'; this.oauthService.clientId = "sampleClientId"; this.oauthService.scope = "read write foo bar"; this.oauthService.setStorage(sessionStorage); this.oauthService.tryLogin({}); } obtainAccessToken(){ this.oauthService.initImplicitFlow(); } getResource(resourceUrl) : Observable<Foo>{ var headers = new Headers({'Content-type': 'application/x-www-form-urlencoded; charset=utf-8', 'Authorization': 'Bearer '+this.oauthService.getAccessToken()}); var options = new RequestOptions({ headers: headers }); return this._http.get(resourceUrl, options) .map((res:Response) => res.json()) .catch((error:any) => Observable.throw(error.json().error || 'Server error')); } isLoggedIn(){ if (this.oauthService.getAccessToken() === null){ return false; } return true; } logout() { this.oauthService.logOut(); location.reload(); } }
4.2. Home Component
Our HomeComponent to handle our simple Home Page:
@Component({ selector: 'home-header', providers: [AppService], template: ` <button *ngIf="!isLoggedIn" (click)="login()" type="submit">Login</button> <div *ngIf="isLoggedIn"> <span>Welcome !!</span> <a (click)="logout()" href="#">Logout</a> <br/> <foo-details></foo-details> </div>` }) export class HomeComponent { public isLoggedIn = false; constructor( private _service:AppService){} ngOnInit(){ this.isLoggedIn = this._service.isLoggedIn(); } login() { this._service.obtainAccessToken(); } logout() { this._service.logout(); } }
4.3. Foo Component
Our FooComponent is exactly the same as in the password flow module.
4.4. App Module
Finally, our AppModule:
@NgModule({ declarations: [ AppComponent, HomeComponent, FooComponent ], imports: [ BrowserModule, FormsModule, HttpModule, OAuthModule.forRoot(), RouterModule.forRoot([ { path: '', component: HomeComponent }]) ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
5. Run the Front End
1. To run any of our front end modules, we need to build the app first:
mvn clean install
2. Then we need to navigate to our Angular app directory:
cd src/main/resources
3. Finally we will start our app:
npm start
The server will start by default on port 4200, to change port of any module change the
"start": "ng serve"
in package.json to make it run on port 8086 for example:
"start": "ng serve --port 8086"
6. Conclusion
In this quick tutorial, we saw how we can upgrade an AngularJS application to one using an Angular4 front-end.
As always, the full source code can be found over on GitHub.