Angular 2 and ASP.Net Web API Authentication

Building real word application needs security.  If you have a decoupled application like Angular 2 with ASP.Net Web API data provider, securing your components, pages and API is not as easy as providing method annotations and saving to cookies.  It needs token for every access.  Here are the steps in making this awesome application happens:

First you must enable CORS settings in your Web API application by providing these entries in to your web.config file:

  <system.webServer>
   <httpProtocol>
    <customHeaders>
      <add name="Access-Control-Allow-Origin" value="*" />
      <add name="Access-Control-Allow-Headers" value="Content-Type" />
      <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
    </customHeaders>
  </httpProtocol> 
  </system.webServer>

Note: Web API security is beyond the scope of this blog.  Our main focus is Angular 2 client security.

Now lets build our Angular 2 application.  Just make a directory and named it: angular2-auth-sample.  Our editor is Visual Studio Code, to launch we type in code .

Untitled

The first file that we will create is the package.json (Node/Angular dependency packages).

{
  "name": "angular2-quickstart",
  "version": "1.0.0",
  "scripts": {
    "start": "concurrently \"npm run tsc:w\" \"npm run lite\" ",
    "tsc": "tsc",
    "tsc:w": "tsc -w",
    "lite": "lite-server",
    "typings": "typings",
    "postinstall": "typings install"
  },
  "license": "HGM",
  "dependencies": {
    "angular2": "2.0.0-beta.9",
    "angular2-jwt": "0.1.8",
    "systemjs": "0.19.24",
    "es6-promise": "^3.0.2",
    "es6-shim": "^0.33.3",
    "reflect-metadata": "0.1.2",
    "jwt-decode": "^1.5.1",
    "rxjs": "5.0.0-beta.2",
    "zone.js": "0.5.15"
  },
  "devDependencies": {
    "concurrently": "^2.0.0",
    "lite-server": "^2.1.0",
    "typescript": "^1.8.7",
    "typings":"^0.7.5"
  }
}

The second file that needs to be ctreated is the  tsconfig.json (Typescript settings).  Angular 2 is written in Typescript, these settings enables Visual Studio Code to transpile Typescript code to Javascript.

{
  "compilerOptions": {
    "target": "es5",
    "module": "system",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": false
  },
  "exclude": [
    "node_modules",
    "typings/main",
    "typings/main.d.ts"
  ]
}

The third and final file that needs to be created is the typings.json.

{
  "ambientDependencies": {
    "es6-shim": "github:DefinitelyTyped/DefinitelyTyped/es6-shim/es6-shim.d.ts#4de74cb527395c13ba20b438c3a7a419ad931f1c",
    "jasmine": "github:DefinitelyTyped/DefinitelyTyped/jasmine/jasmine.d.ts#d594ef506d1efe2fea15f8f39099d19b39436b71"
  }
}

Now that we’ve created the three files, our Visual Studio Code editor will look like this (see image below):

Untitled1

Now run npm install to install the packages.  Installing the packages may take more than a minute depending on your Internet connection.

Untitled3

Once done, its time to write the code!

The first code that we are going to write is the index.html file.


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="">
    <meta name="author" content="">
    
    <title>angular2-auth-sample</title>
    
    <!-- Base href routing -->
    <script>document.write('<base href="' + document.location + '" />');</script>
   
    <!-- Standard Angular 2 Modules + Routing + Http -->
    <script src="node_modules/es6-shim/es6-shim.min.js"></script>
    <script src="node_modules/systemjs/dist/system-polyfills.js"></script>
    <script src="node_modules/angular2/es6/dev/src/testing/shims_for_IE.js"></script>   

    <script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>
    <script src="node_modules/systemjs/dist/system.src.js"></script>
    <script src="node_modules/rxjs/bundles/Rx.js"></script>
    <script src="node_modules/angular2/bundles/angular2.dev.js"></script>

    <script src="node_modules/angular2/bundles/router.dev.js"></script>
    
    <script src="node_modules/angular2/bundles/http.dev.js"></script>
    
    <!-- Configure SystemJS -->
    <script>
      System.config({
        packages: {        
          app: {
            format: 'register',
            defaultExtension: 'js'
          }
        }
      });
      System.import('app/main').then(null, console.error.bind(console));
    </script>     
</head>

<body>
    
    <app>Loading...</app>

</body>

</html>

Now that our Index.html file is ready!  It’s time to write the real Angular 2 codes.  But first we must create a directory structure.  For the structure see the image below:

Untitled4

At the root of our app folder we will create our main.ts component. The main.ts component boots the entire Angular 2 application:

import { bootstrap } from 'angular2/platform/browser';
import { App } from './app/app';

bootstrap(App);

As you can see the main.ts component just calls on the app.ts component in the app folder, which leads us to our next code:

import { Component } from 'angular2/core';
import { RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS } from 'angular2/router';
import { Http } from 'angular2/http';

import { HomeComponent } from '../home/home';
import { LoginComponent } from '../login/login';
import { DashboardComponent } from '../dashboard/dashboard';

@Component({
  selector: 'app',
  template: `
        <h3>{{title}}</h3>
        <br/>
        <a [routerLink]="['Home']">Home</a>
        <a [routerLink]="['Login']">Login</a>
        <a [routerLink]="['Dashboard']">Dashboard</a> 
        <br/>
        <router-outlet></router-outlet>
  `,
  directives: [ROUTER_DIRECTIVES],
  providers: [
    ROUTER_PROVIDERS
  ]
})
@RouteConfig([
  {
    path: '/home',
    name: 'Home',
    component: HomeComponent,
    useAsDefault: true
  },
  {
    path: '/login',
    name: 'Login',
    component: LoginComponent
  },
  {
    path: '/dashboard',
    name: 'Dashboard',
    component: DashboardComponent
  }
])
export class App {
    private title = 'App';
}

In the above code, we import the Router and Http Angular 2 components.  Then we configure our Route. Very Important! take note of the template, you should put in a tag named router-outlet. This tag will provide outlet for all subsequent Angular 2 components.

Our home.ts component is a public component, meaning, anyone can access it.  Aside from that I made it to display the Token information.  So if the user is not logged-in, there are no information, otherwise you’ll see the entire token information.  Warning!  token information may differ from provider to provider, we are using ASP.Net Web API Membership Authentication Token.

import {Component} from 'angular2/core';

@Component({
    selector: 'home',
    template: `
        <h4>Home</h4>
        <br/>
        <p>Token:<b>{{access_token}}</b></p>
        <p>Expires In:<b>{{expires_in}}</b></p>
        <p>Token Type:<b>{{token_type}}</b></p>
        <p>Username:<b>{{userName}}</b></p>    
    `
})
export class HomeComponent {
    private access_token = localStorage.getItem('access_token');
    private expires_in = localStorage.getItem('expires_in');
    private token_type = localStorage.getItem('token_type');
    private userName = localStorage.getItem('userName');     
}

The next component is the login.ts component.  This is where you let your user type in the username and password and get authenticated through your API.

import {Component} from 'angular2/core';
import {Http, Headers, RequestOptions, HTTP_PROVIDERS} from 'angular2/http';
import {Router} from 'angular2/router';

@Component({
    selector: 'login',
    template: `
        <h4>Login</h4>
        <br/>
        <form role="form" (submit)="login($event, username.value, password.value)">
            <input type="text" #username id="username" required="required" placeholder="Username"> <br/>
            <input type="password" #password id="password" required="required" placeholder="Password"> <br/>
            <button type="submit">Login</button> <br/>
        </form>
    `,
    providers: [
        HTTP_PROVIDERS
    ]    
})
export class LoginComponent {
    private title = 'Login';

    constructor(private _router: Router,  private _http: Http) {
    }   
      
    login(event, username, password) {
        event.preventDefault();
        
        let url = "http://[Your URL]";
        let body = "username=" + username + "&password=" + password + "&grant_type=password";
        let headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' });
        let options = new RequestOptions({ headers: headers });        
        
        this._http.post(url, body, options).subscribe(
            response => {
                localStorage.setItem('access_token', response.json().access_token);
                localStorage.setItem('expires_in', response.json().expires_in);
                localStorage.setItem('token_type', response.json().token_type);
                localStorage.setItem('userName', response.json().userName);
                this._router.navigate(['Dashboard']);
            },
            error => {
                alert(error.text());
                console.log(error.text());
            }
        );
    }    
}

Very important to include HTTP_PROVIDERS in the class annotation and a constructor with two parameters, the router and http variables. Take note also of the template, it is just an ordinary HTML form entry except for the (submit) tag that calls on the method login in our login.ts component.  In the method login we execute the http.post function, to post entries of our login form to our API for authentication.  If successful, we saved the token in our localStorage.  Thats how simple to logged in users using Angular 2.

The dashboard.ts component is a private component, meaning you need to logged in before you could open this component.

import {Component, OnInit} from 'angular2/core';
import {Router} from 'angular2/router';

@Component({
    selector: 'dashboard',
    template: `
<h4>Dashboard</h4>
<form role="form" (submit)="logout()">
            <button type="submit" class="btn btn-danger btn-lg">Logout</button>
        </form>

    `
})
export class DashboardComponent implements OnInit {
    constructor(private _router: Router) {
    }
    ngOnInit() {
        if (!localStorage.getItem('access_token')) {
            this._router.navigate(['Login']);
        }
    }
    logout() {
        localStorage.removeItem('access_token');
        localStorage.removeItem('expires_in');
        localStorage.removeItem('token_type');
        localStorage.removeItem('userName');

        this._router.navigate(['Login']);
    }
}

The above code is easy to read.  What is important here is the implementation of the ngOnInit method, which we just check for the localStorage access_token and if empty we route the component back to login.ts component.

Thats it!  To summarize, we have three basic components; home.ts (public component), login.ts (public component) and dashboard.ts (private/secure component).  To secure the component we just need to implement the ngOnInit method.  Very Simple!

A pinch of CSS and Twitter Bootstrap template you could have this:

Happy Coding! And if you find this blog helpful, you can make the donation by clicking the Paypal button below.


					
Advertisements
About

Software developer living in the Philippines.

Posted in ASP.NET
5 comments on “Angular 2 and ASP.Net Web API Authentication
  1. Tony says:

    Hi, I am having a problem with this code. I replace let url = “http://[Your URL]”; with my url, for example I have my webapi running on port 5100, so it’s “http://localhost:5100” and it fails with a 404 not found. I’ve also tried http://localhost:5100/SampleData/Sample which is a controller and method I set up. Still no success. Any idea what I might be doing wrong?

  2. Great post. Couldnt get any easier. Can you please update to Angular 2.0 version.

  3. Very helpful post. Well structured and scope and purpose clearly defined. Thanks!

  4. Maxxx says:

    What about the .Net part? All this shows is how to consume the token – and not how to create it in .Net, or how to send it with future API requests? Is there another part to this?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Author

Harold Glenn P. Minerva
Software Developer / Tech Enthusiast
Living in the Philippines

View Harold Glenn Minerva's profile on LinkedIn

Instagram

Software Engineer - Seasonal and Range Trading Software. Magenta Trader is a powerful stock market visualization software that increases your probability of trading success.

Software Architect and Founder - Easyfis.com is a multi-tenant cloud-based Software-as-a-Service (SaaS) business app that caters to micro, small and medium trading businesses.

CTO and Co-Founder - We give your company the leverage by providing innovative software solutions products such as Point-of-Sales (POS), Financial Information System (FMIS), Payroll and DTR (HRIS), and many more.

%d bloggers like this: