Release notes

v2.0.0 (17-12-2019)
  • Complete rewrite of the tutorial after implementing security for learninggoals UI part

v1.0.0 (08-12-2017)
  • Initial version

Introduction

What you will learn

In this tutorial you will learn
  • The theory behind connecting an Angular UI to a Spring Boot Secure API

    • What a Guard in Angular is and how to use the CanActivateGuard class

  • Some technical and to security related topics

    • What localstorage is and how to work with it

    • How to send a jwt token using an Angular client

    • How to use the environment(s) of an Angular application

Roadmap and Steps
  • I prefer to use a roadmap and steps during this document

    • Roadmap: a coarse grained way to accomplish something

    • Steps: a fine grained way to accomplish something. These steps should be executed.

Start learning a secure UI

Topic: localStorage

Introduction

During this section we will learn what localStorage is.

What you will learn

In the next section of this tutorial you will learn
  • What the localStorage on a browser is

  • How to handle it in JavaScript

  • How to handle it in Angular

Why: localStorage

Cookies are intended for communication with server; they are automatically added to all requests and can be accessed by both the server and client side.

Web storage falls exclusively under the purview of client-side scripting. Web storage data is not automatically transmitted to the server in every HTTP request, and a web server can’t directly write to Web storage. However, either of these effects can be achieved with explicit client-side scripts, allowing for fine-tuning of the desired interaction with the server.

What: localStorage

Web storage, sometimes known as DOM storage (Document Object Model storage), provides web apps with methods and protocols for storing client-side data.

Web storage supports persistent data storage, similar to cookies but with a greatly enhanced capacity and no information stored in the HTTP request header. There are two main web storage types: local storage and session storage, behaving similarly to persistent cookies and session cookies respectively.

Web storage is standardized by the World Wide Web Consortium (W3C). All major browsers support it.

How: localStorage

Web storage offers two different storage areas—local storage and session storage—which differ in scope and lifetime. Data placed in local storage is per origin—the combination of protocol, host name, and port number as defined in the same-origin policy.

The data is available to all scripts loaded from pages from the same origin that previously stored the data and persists after the browser is closed. As such, Web storage does not suffer from cookie Weak Integrity and Weak Confidentiality issues, described in RFC 6265 sections 8.5 and 8.6. Session storage is both per-origin and per-instance (per-window or per-tab) and is limited to the lifetime of the instance. Session storage is intended to allow separate instances of the same web app to run in different windows without interfering with each other, a use case that’s not well supported by cookies.

Follow-up: localStorage

Below you find for this topic some extra resources to read or watch

Topic: Fetch a JWT

Introduction

The first thing we have to learn is how we can get a JWT from the Spring Boot REST api.

What you will learn

In the next section of this tutorial you will learn
  • How to perform a POST request to the auth endpoint of the Spring Boot api

Why: Fetch a JWT

The basics of a JWT is to have a token stored on the client side. The server is not even aware of the tokens it has send out. The Client has to store the token somewhere, which we will handle in the next section, and send the token with the subsequent requests. That is why we have to fetch a JWT from the server.

How: Fetch a JWT

Roadmap
  • Post to the auth endpoint

  • The JWT token will be received

Steps
  • We will send a request like this

  • We will receive a response like this

    • body: { "token": "eyJhbGciOiJIUzUxMiJ9.eyJzd …​ "}

Topic: Store a JWT

Introduction

In the previous section we learned that we can store some in the localStorage. During this section we will learn how to store the JWT in the localStorage

What you will learn

In the next section of this tutorial you will learn
  • How to handle the returned JWT

  • How to store the JWT in the localStorage

Why: Store a JWT

We have to store the JWT in localStorage to resend it will the subsequent requests

How: Store a JWT

Consider the following code (a snippet from the login method of the authentication.service.ts)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
login(username: string, password: string): Observable<boolean> {

    let result:Observable<boolean> = this.http.post<Token>(this.authUrl, { username: username, password: password })
    .pipe(map(tokenResult => {
      let token = tokenResult.token;
      if (token) {
        // store username and jwt token in local storage to keep user logged in between page refreshes
        localStorage.setItem('currentUser', JSON.stringify({ username: username, token: token }));

        // return true to indicate successful login
        return true;
      } else {
        // return false to indicate failed login
        return false;
      }
    }),
    catchError(err => {
      console.error(err);
      return of(false);
    }));

    return result;
  }
Explanation
  • On line 8 we see that we use plain javascript to store the token in the localstorage. That’s all there is to it!

Topic: Http Interceptor

Introduction

In this section we will learn what the benefits are of using an Http Interceptor.

What you will learn

In the next section of this tutorial you will learn
  • What an Http Interceptor is

  • Why we are going to use it

  • How to use it - in general terms

Why: Http Interceptor

The goal of an Http Interceptor is to do some work after the request has been send out by the Angular Http Client. In fact it is some final PRE work before sending out the request to the Spring Boot REST api.

When: Http Interceptor

We can use the Http Interceptor in our case to add the Authorization header with the JWT to the request. So we do not have to add code to every service which is sending an Http Request. We can just add the Http Interceptor and every http call is led through the interceptor before it leaves our machine

What: Http Interceptor

An Http Interceptor is a class which implements the Angular HttpInterceptor interface, is registered in app.module.ts and will then run before(PRE) or after(POST) every http request.

Showing the flow through the HttpInterceptor

http interceptor

How: Http Interceptor

Roadmap
  • Create a class AuthInterceptor which implements the HttpInterceptor interface

  • Implement the intercept(…​) method

  • Register the interceptor

Steps - create the class AuthInterceptor and implement the intercept method
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from "@angular/common/http";
import { Observable } from "rxjs";
import { Injectable } from '@angular/core';
import { AuthenticationService } from '../service/authentication.service';

@Injectable({
    providedIn: 'root'
})
export class AuthInterceptor implements HttpInterceptor {

    constructor(private authenticationService: AuthenticationService) {

    }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

        let token:string = this.authenticationService.getToken();

        const cloneReq = req.clone({
            headers: req.headers.set(
                'Authorization',
                'Bearer ' + token
            )
        });
        return next.handle(cloneReq);
    }
}
Steps - register the interceptor in app.module.ts (import and add to providers)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
...
// imports regarding the interceptor
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { AuthInterceptor } from './interceptor/auth.interceptor';
import { UserShowComponent } from './components/user-show/user-show.component';
.
.
.
 providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AuthInterceptor,
      multi: true // only necessary when using more than one interceptor.
    },
  ],
.
.
.
Explaination
  • the multi above means, are there more than one entry in this JSON list

Follow-up: Http Interceptor

Below you find for this topic some extra resources to watch

Topic: CanActivate

Introduction

In this section we will introduce the principle regarding the Guards of Angular.

A guard in Angular is used to prevent a component from being loaded when the authorization dictates otherwise.

What you will learn

In the next section of this tutorial you will learn
  • The principle of Angular guards

  • What the CanActivate guard can do for us

  • How to implement the CanActivate guard

Why and When: CanActivate

We can use a guard to prevent a component from being loaded

What: CanActivate

An canactivate guard in general in Angular is a class which implements the interface CanActivate and his method canActivate(…​)

The canActivate method should return a boolean whether or not wrapped in an Observable or Promise.

If it returns true ⇒ the component on which the guard plumbed will be invoked If it returns false ⇒ the component on which the guard is not invoked AND the guard should navigate to a page which is different than the component e.g. login

Diagram of Angular’s Route Guard

angular route guard

How: CanActivate

For more information regarding Guards see this links on my Angular training course ⇒

Resources: CanActivate

Below you find for this topic some extra resources to watch and read

Topic: Environments

Introduction

In this section we will learn how to can use an Angular application in multiple environments, e.g. development, test, acceptance and production

In Angular, the term environments in replaced by configurations since Angular 6+.

What you will learn

In the next section of this tutorial you will learn
  • Why we have multiple environments

  • How to use them

  • How to configure them in an Angular application

Please read this link carefully regarding configuration and also read this link regarding deployment

Topic: Send a JWT

Introduction

In the previous sections we learned how to fetch a JWT and to store a JWT. During this section you will learn how to get the stored JWT and send it with the request for getting data from the Spring Boot API.

What you will learn

In the next section of this tutorial you will learn
  • How to get the stored JWT and put that in the request

Why: Send a JWT

We have to send out the JWT so that the Spring Boot REST api knows that we are legal to invoke an API call

What: Send a JWT

What to do
  • Read out the JWT from the localStorage

  • During sending add the Authorization header to the request which contains the JWT

    • 'Authorization': 'Bearer eyJhbGciOiJIUzUxMiJ9.eyJz …​ '

How: Send a JWT

We implement a HttpInterceptor as shown in the theory above to the code. That will deliver the JWT per request

HttpInterceptor (same as above)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from "@angular/common/http";
import { Observable } from "rxjs";
import { Injectable } from '@angular/core';
import { AuthenticationService } from '../service/authentication.service';

@Injectable({
    providedIn: 'root'
})
export class AuthInterceptor implements HttpInterceptor {

    constructor(private authenticationService: AuthenticationService) {

    }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

        let token:string = this.authenticationService.getToken();

        const cloneReq = req.clone({
            headers: req.headers.set(
                'Authorization',
                'Bearer ' + token
            )
        });
        return next.handle(cloneReq);
    }
}

Start implementing a secure UI

Overview

During the upcoming section we will implement the following structure, see image

angular to springboot using interceptor
Figure 1. Implementing a Secure UI

Add class Authority

The goal of the class Authority is to model a class which contains the Authority

Authority
1
2
3
export class Authority {
    authority:string;
}

Add class JwtUser

The goal of the class JwtUser is to model a class which contains the username and fullName and authorities of a given JwtUser.

JwtUser
1
2
3
4
5
6
7
8
9
import { Authority } from './authority';

export class JwtUser {

    username:string;
    fullName:string;

    authorities: Authority[];
}

Modify app-routing.module.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

import { HomeComponent } from './home/home.component';
import { DashboardComponent } from './dashboard/dashboard.component';
import { HeroesComponent } from './heroes.component';
import { HeroDetailComponent } from './hero-detail/hero-detail.component';
import { LoginComponent}  from './login/login.component';

import { CanActivateGuard } from './can-activate.guard';

const routes: Routes = [
  { path: '', redirectTo: '/home', pathMatch: 'full' },
  { path: 'login', component: LoginComponent},
  { path: 'home', component: HomeComponent },
  { path: 'dashboard', component: DashboardComponent, canActivate: [CanActivateGuard] },
  { path: 'detail/:id', component: HeroDetailComponent, canActivate: [CanActivateGuard] },
  { path: 'heroes', component: HeroesComponent, canActivate: [CanActivateGuard] }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule {

}

Add to app.module.ts

Add
  • Import Home and LoginComponent

  • Import AuthenticationService and CanActivateGuard

  • Add Home and LoginComponent to the declarations array

  • Add AuthencationService and CanActivateGuard to the providers array

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import { NgModule }       from '@angular/core';
import { BrowserModule }  from '@angular/platform-browser';
import { FormsModule }    from '@angular/forms';

import { AppComponent }         from './app.component';
import { DashboardComponent }   from './dashboard/dashboard.component';
import { HeroDetailComponent }  from './hero-detail/hero-detail.component';
import { HeroesComponent }      from './heroes.component';
import { HeroService }          from './hero.service';
import { HttpModule }           from '@angular/http';

import { AppRoutingModule }     from './app-routing.module';

// Imports for loading & configuring the in-memory web api
import { InMemoryWebApiModule } from 'angular-in-memory-web-api';
import { InMemoryDataService }  from './in-memory-data.service';
import { HeroSearchComponent } from './hero-search/hero-search.component';
import { HomeComponent } from './home/home.component';
import { LoginComponent } from './login/login.component';
import { AuthenticationService} from './authentication.service';

import { CanActivateGuard } from './can-activate.guard';

// http interceptors  => see also below under 'providers'
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { AuthInterceptor } from './interceptor/auth.interceptor';
import { UserShowComponent } from './components/user-show/user-show.component';



@NgModule({
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    // InMemoryWebApiModule.forRoot(InMemoryDataService),
    AppRoutingModule
  ],
  declarations: [
    AppComponent,
    DashboardComponent,
    HeroDetailComponent,
    HeroesComponent,
    HeroSearchComponent,
    HomeComponent,
    LoginComponent
  ],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AuthInterceptor,
      multi: true // only necessary when using more than one interceptor. // now it is here for documentation.
    }
  ],
  bootstrap: [ AppComponent ]
})
export class AppModule { }

Modify app.component.html

<h6 class="version">{{appVersion}}</h6>
<h1>{{title}}</h1>
<nav>
    <a routerLink="/home" routerLinkActive="active">Home</a>
    <a routerLink="/dashboard" routerLinkActive="active">Dashboard</a>
    <a routerLink="/heroes" routerLinkActive="active">Heroes</a>
    <a routerLink="/login" routerLinkActive="active">Login</a>
</nav>
<router-outlet></router-outlet>

Modify the other components

Modify dashboard.component.ts

Changes
  • Add router to constructor

  • Expand ngOnInit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import { Component, OnInit } from '@angular/core';
import { Hero } from '../hero';
import { HeroService } from '../hero.service';
import { Router } from '@angular/router';

@Component({
  moduleId: module.id,
  selector: 'my-dashboard',
  templateUrl: './dashboard.component.html',
  providers: [HeroService],
  styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent implements OnInit {
  heroes: Hero[] = [];

  constructor(private router: Router, private heroService: HeroService) {
  }

  ngOnInit(): void {
    this.heroService.getHeroes()
      .then(
        heroes => this.heroes = heroes.slice(0, 4),
        error => {
          this.router.navigate(['login']);
          console.error('An error occurred in dashboard component, navigating to login: ', error);
        }
      );
  }
}

Modify heroes.component.ts

Changes
  • getHeroes method is extended with an error callback handler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import { Component } from '@angular/core';
import { Hero } from './hero';
import { HeroService } from './hero.service';
import { OnInit } from '@angular/core';
import { Router } from '@angular/router';

@Component({
  moduleId: module.id,
  selector: 'my-heroes',
  templateUrl: './heroes.component.html',
  styleUrls: ['./heroes.component.css'],
  providers: [HeroService]

})
export class HeroesComponent implements OnInit {
    heroes: Hero[];
    selectedHero: Hero;

    constructor(private router: Router, private heroService: HeroService){ }

    ngOnInit(): void {
      this.getHeroes();
  }

    getHeroes(): void {
      this.heroService.getHeroes()
      .then(
        heroes => this.heroes = heroes,
        error => {
        this.router.navigate(['login']);
        console.error('An error occurred in heroes component, navigating to login: ', error);
        }
      )
  }


    onSelect(hero: Hero): void {
        this.selectedHero = hero;
    }

    gotoDetail(): void {
      this.router.navigate(['/detail', this.selectedHero.id]);
  }

  add(name: string): void {
    name = name.trim();
    if(name) {
    this.heroService.create(name)
      .then(hero => {
        this.heroes.push(hero);
        this.selectedHero = null;
      });
    }
  }

  delete(hero: Hero): void {
      this.heroService
      .delete(hero.id)
      .then(() => {
          this.heroes = this.heroes.filter(h => h !== hero);
          if(this.selectedHero === hero) {
            this.selectedHero = null;
        }
      });
  }
}

Add home.component.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'home',
  moduleId: module.id,
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

}

Add login.component.css

.alert {
    width:200px;
    margin-top:20px;
    margin-bottom:20px;
  }

  .alert.alert-info {
    color:#607D8B;
  }

  .alert.alert-error {
    color:red;
  }

  .help-block {
    width:200px;
    color:white;
    background-color:gray;
  }

  .form-control {
    width: 200px;
    margin-bottom:10px;
  }

  .btn {
    margin-top:20px;
  }

Add login.component.html

<div class="col-md-6 col-md-offset-3">
    <h2>Login</h2>

    <div class="alert alert-info">
        Username: admin<br/>
        Password: admin
    </div>

    <form name="form" (ngSubmit)="f.form.valid && login()" #f="ngForm" novalidate>
        <div class="form-group" [ngClass]="{ 'has-error': f.submitted && !username.valid }">
            <label for="username">Username</label>
            <input type="text" class="form-control" name="username" [(ngModel)]="model.username" #username="ngModel" required />
            <span *ngIf="f.submitted && !username.valid" class="help-block">Username is required</span>
        </div>
        <div class="form-group" [ngClass]="{ 'has-error': f.submitted && !password.valid }">
            <label for="password">Password&nbsp;</label>
            <input type="password" class="form-control" name="password" [(ngModel)]="model.password" #password="ngModel" required />
            <span *ngIf="f.submitted && !password.valid" class="help-block">Password is required</span>
        </div>
        <div class="form-group">
            <button [disabled]="loading" class="btn btn-primary">Login</button>
            <img *ngIf="loading" src="data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA==" />
        </div>
        <div *ngIf="error" class="alert alert-error">{{error}}</div>
    </form>
</div>

Add login.component.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';

import { AuthenticationService } from '../authentication.service';

@Component({
    moduleId: module.id,
    templateUrl: './login.component.html',
    styleUrls: ['./login.component.css']
})

export class LoginComponent implements OnInit {
    model: any = {};
    loading = false;
    error = '';

    constructor(
        private router: Router,
        private authenticationService: AuthenticationService) { }

    ngOnInit() {
        // reset login status
        this.authenticationService.logout();
    }

    login() {
        this.loading = true;
                this.authenticationService.logout();
        this.authenticationService.login(this.model.username, this.model.password)
            .subscribe(result => {
                if (result === true) {
                    // login successful
                    this.router.navigate(['home']);
                } else {
                    // login failed
                    this.error = 'Username or password is incorrect';
                    this.loading = false;
                }
            }, error => {
              this.loading = false;
              this.error = error;
            });
    }
}
Below you find the code for the AuthenticationService
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import { Injectable } from '@angular/core';
import { environment } from 'src/environments/environment';
import { HttpClient, HttpResponse } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { Token } from '../domain/token';
import {  map, catchError, filter } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class AuthenticationService {

  private authUrl: string = environment.authUrl;  // URL to auth api

  constructor(private http: HttpClient) {

  }

  login(username: string, password: string): Observable<boolean> {

    let result:Observable<boolean> = this.http.post<Token>(this.authUrl, { username: username, password: password })
    .pipe(map(tokenResult => {
      let token = tokenResult.token;
      if (token) {
        // store username and jwt token in local storage to keep user logged in between page refreshes
        localStorage.setItem('currentUser', JSON.stringify({ username: username, token: token }));

        // return true to indicate successful login
        return true;
      } else {
        // return false to indicate failed login
        return false;
      }
    }),
    catchError(err => {
      console.error(err);
      return of(false);
    }));

    return result;
  }

  getToken(): string {
    var currentUser = JSON.parse(localStorage.getItem('currentUser'));
    var token = currentUser && currentUser.token;

    return token ? token : "";
  }

  isLoggedIn(): boolean {
    var token: string = this.getToken();
    return token && token.length > 0;
  }

  logout(): void {
    // clear token remove user from local storage to log user out
    localStorage.removeItem('currentUser');
  }
}
You can generate the skeleton of this service by invoking
        $ ng generate service authentication
Explanation
  • In the login method above there is a post which will post the username and password to the REST api for validation

  • If successful ⇒ We use the pipe method to pipe the returned Observable through a pipe and map the tokenResult (WebResult) to a String. That string is than persisted to localStorage

  • If not successful ⇒ We just return false to indicate a failed login

Add CanActivateGuard

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { Router } from '@angular/router';
import { AuthenticationService } from './authentication.service';

@Injectable({
  providedIn: 'root'
})
export class CanActivateGuard implements CanActivate {

  constructor(
    private router: Router,
    private authenticationService: AuthenticationService) {
  }

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {

      if(this.authenticationService.isLoggedIn()) {
        return true;
      }
      else {
        this.router.navigate(['/login']);
        return false;
      }
  }
}
You can generate a guard by issuing the following
1
        $ ng generate guard can-activate

Add class AuthInterceptor

Auth interceptor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from "@angular/common/http";
import { Observable } from "rxjs";
import { Injectable } from '@angular/core';
import { AuthenticationService } from '../service/authentication.service';

@Injectable({
    providedIn: 'root'
})
export class AuthInterceptor implements HttpInterceptor {

    constructor(private authenticationService: AuthenticationService) {}

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

        let token:string = this.authenticationService.getToken();

        const cloneReq = req.clone({
            headers: req.headers.set(
                'Authorization',
                'Bearer ' + token
            )
        });
        return next.handle(cloneReq);
    }
}

Resources

Links regarding the tutorial