English 中文(简体)
Authentication and Authorization
  • 时间:2024-09-17

Angular 8 - Authentication and Authorization


Previous Page Next Page  

Authentication is the process matching the visitor of a web apppcation with the pre-defined set of user identity in the system. In other word, it is the process of recognizing the user’s identity. Authentication is very important process in the system with respect to security.

Authorization is the process of giving permission to the user to access certain resource in the system. Only the authenticated user can be authorised to access a resource.

Let us learn how to do Authentication and Authorization in Angular apppcation in this chapter.

Guards in Routing

In a web apppcation, a resource is referred by url. Every user in the system will be allowed access a set of urls. For example, an administrator may be assigned all the url coming under administration section.

As we know already, URLs are handled by Routing. Angular routing enables the urls to be guarded and restricted based on programming logic. So, a url may be denied for a normal user and allowed for an administrator.

Angular provides a concept called Router Guards which can be used to prevent unauthorised access to certain part of the apppcation through routing. Angular provides multiple guards and they are as follows:

    CanActivate − Used to stop the access to a route.

    CanActivateChild − Used to stop the access to a child route.

    CanDeactivate − Used to stop ongoing process getting feedback from user. For example, delete process can be stop if the user reppes in negative.

    Resolve − Used to pre-fetch the data before navigating to the route.

    CanLoad − Used to load assets.

Working example

Let us try to add login functionapty to our apppcation and secure it using CanActivate guard.

Open command prompt and go to project root folder.


cd /go/to/expense-manager

Start the apppcation.


ng serve

Create a new service, AuthService to authenticate the user.


ng generate service auth
CREATE src/app/auth.service.spec.ts (323 bytes)
CREATE src/app/auth.service.ts (133 bytes)

Open AuthService and include below code.


import { Injectable } from  @angular/core ;

import { Observable, of } from  rxjs ;
import { tap, delay } from  rxjs/operators ;

@Injectable({
   providedIn:  root 
})
export class AuthService {

   isUserLoggedIn: boolean = false;

   login(userName: string, password: string): Observable {
      console.log(userName);
      console.log(password);
      this.isUserLoggedIn = userName ==  admin  && password ==  admin ;
      localStorage.setItem( isUserLoggedIn , this.isUserLoggedIn ? "true" : "false"); 

   return of(this.isUserLoggedIn).pipe(
      delay(1000),
      tap(val => { 
         console.log("Is User Authentication is successful: " + val); 
      })
   );
   }

   logout(): void {
   this.isUserLoggedIn = false;
      localStorage.removeItem( isUserLoggedIn ); 
   }

   constructor() { }
}

Here,

    We have written two methods, login and logout.

    The purpose of the login method is to vapdate the user and if the user successfully vapdated, it stores the information in localStorage and then returns true.

    Authentication vapdation is that the user name and password should be admin.

    We have not used any backend. Instead, we have simulated a delay of 1s using Observables.

    The purpose of the logout method is to invapdate the user and removes the information stored in localStorage.

Create a login component using below command −


ng generate component login
CREATE src/app/login/login.component.html (20 bytes)
CREATE src/app/login/login.component.spec.ts (621 bytes)
CREATE src/app/login/login.component.ts (265 bytes)
CREATE src/app/login/login.component.css (0 bytes)
UPDATE src/app/app.module.ts (1207 bytes)

Open LoginComponent and include below code −


import { Component, OnInit } from  @angular/core ;

import { FormGroup, FormControl } from  @angular/forms ;
import { AuthService } from  ../auth.service ;
import { Router } from  @angular/router ;

@Component({
   selector:  app-login ,
   templateUrl:  ./login.component.html ,
   styleUrls: [ ./login.component.css ]
})
export class LoginComponent implements OnInit {

   userName: string;
   password: string;
   formData: FormGroup;

   constructor(private authService : AuthService, private router : Router) { }

   ngOnInit() {
      this.formData = new FormGroup({
         userName: new FormControl("admin"),
         password: new FormControl("admin"),
      });
   }

   onCpckSubmit(data: any) {
      this.userName = data.userName;
      this.password = data.password;

      console.log("Login page: " + this.userName);
      console.log("Login page: " + this.password);

      this.authService.login(this.userName, this.password)
         .subscribe( data => { 
            console.log("Is Login Success: " + data); 
      
           if(data) this.router.navigate([ /expenses ]); 
      });
   }
}

Here,

    Used reactive forms.

    Imported AuthService and Router and configured it in constructor.

    Created an instance of FormGroup and included two instance of FormControl, one for user name and another for password.

    Created a onCpckSubmit to vapdate the user using authService and if successful, navigate to expense pst.

Open LoginComponent template and include below template code.


<!-- Page Content -->
<span class="container">
   <span class="row">
      <span class="col-lg-12 text-center" style="padding-top: 20px;">
         <span class="container box" style="margin-top: 10px; padding-left: 0px; padding-right: 0px;">
            <span class="row">
               <span class="col-12" style="text-apgn: center;">
                                    <form [formGroup]="formData" (ngSubmit)="onCpckSubmit(formData.value)" 
                                          class="form-signin">
                                    <h2 class="form-signin-heading">Please sign in</h2>
                                    <label for="inputEmail" class="sr-only">Email address</label>
                                    <input type="text" id="username" class="form-control" 
                                          formControlName="userName" placeholder="Username" required autofocus>
                                    <label for="inputPassword" class="sr-only">Password</label>
                                    <input type="password" id="inputPassword" class="form-control" 
                                          formControlName="password" placeholder="Password" required>
                                    <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
                                    </form>
               </span>
            </span>
         </span>
      </span>
   </span>
</span>

Here,

Created a reactive form and designed a login form.

Attached the onCpckSubmit method to the form submit action.

Open LoginComponent style and include below CSS Code.


.form-signin {
   max-width: 330px;

   padding: 15px;
   margin: 0 auto;
}

input {
   margin-bottom: 20px;
}

Here, some styles are added to design the login form.

Create a logout component using below command −


ng generate component logout
CREATE src/app/logout/logout.component.html (21 bytes)
CREATE src/app/logout/logout.component.spec.ts (628 bytes)
CREATE src/app/logout/logout.component.ts (269 bytes)
CREATE src/app/logout/logout.component.css (0 bytes)
UPDATE src/app/app.module.ts (1368 bytes)

Open LogoutComponent and include below code.


import { Component, OnInit } from  @angular/core ;

import { AuthService } from  ../auth.service ;
import { Router } from  @angular/router ;

@Component({
   selector:  app-logout ,
   templateUrl:  ./logout.component.html ,
   styleUrls: [ ./logout.component.css ]
})
export class LogoutComponent implements OnInit {

   constructor(private authService : AuthService, private router: Router) { }

   ngOnInit() {
      this.authService.logout();
      this.router.navigate([ / ]);
   }

}

Here,

    Used logout method of AuthService.

    Once the user is logged out, the page will redirect to home page (/).

Create a guard using below command −


ng generate guard expense
CREATE src/app/expense.guard.spec.ts (364 bytes)
CREATE src/app/expense.guard.ts (459 bytes)

Open ExpenseGuard and include below code −


import { Injectable } from  @angular/core ;
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router, UrlTree } from  @angular/router ;
import { Observable } from  rxjs ;

import { AuthService } from  ./auth.service ;

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

   constructor(private authService: AuthService, private router: Router) {}

   canActivate(
   next: ActivatedRouteSnapshot,
   state: RouterStateSnapshot): boolean | UrlTree {
      let url: string = state.url;

          return this.checkLogin(url);
      }

      checkLogin(url: string): true | UrlTree {
         console.log("Url: " + url)
         let val: string = localStorage.getItem( isUserLoggedIn );

         if(val != null && val == "true"){
            if(url == "/login")
               this.router.parseUrl( /expenses );
            else 
               return true;
         } else {
            return this.router.parseUrl( /login );
         }
      }
}

Here,

    checkLogin will check whether the localStorage has the user information and if it is available, then it returns true.

    If the user is logged in and goes to login page, it will redirect the user to expenses page

    If the user is not logged in, then the user will be redirected to login page.

Open AppRoutingModule (src/app/app-routing.module.ts) and update below code −


import { NgModule } from  @angular/core ;
import { Routes, RouterModule } from  @angular/router ;
import { ExpenseEntryComponent } from  ./expense-entry/expense-entry.component ;
import { ExpenseEntryListComponent } from  ./expense-entry-pst/expense-entry-pst.component ;
import { LoginComponent } from  ./login/login.component ;
import { LogoutComponent } from  ./logout/logout.component ;

import { ExpenseGuard } from  ./expense.guard ;

const routes: Routes = [
   { path:  login , component: LoginComponent },
   { path:  logout , component: LogoutComponent },
   { path:  expenses , component: ExpenseEntryListComponent, canActivate: [ExpenseGuard]},
   { path:  expenses/detail/:id , component: ExpenseEntryComponent, canActivate: [ExpenseGuard]},
   { path:   , redirectTo:  expenses , pathMatch:  full  }
];

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

Here,

    Imported LoginComponent and LogoutComponent.

    Imported ExpenseGuard.

    Created two new routes, login and logout to access LoginComponent and LogoutComponent respectively.

    Add new option canActivate for ExpenseEntryComponent and ExpenseEntryListComponent.

Open AppComponent template and add two login and logout pnk.


<span class="collapse navbar-collapse" id="navbarResponsive">
   <ul class="navbar-nav ml-auto">
      <p class="nav-item active">
         <a class="nav-pnk" href="#">Home
            <span class="sr-only" routerLink="/">(current)</span>

         </a>
      </p>
      <p class="nav-item">
         <a class="nav-pnk" routerLink="/expenses">Report</a>
      </p>
      <p class="nav-item">
         <a class="nav-pnk" href="#">Add Expense</a>
      </p>
      <p class="nav-item">

         <a class="nav-pnk" href="#">About</a>
      </p>
      <p class="nav-item">
                  <span *ngIf="isUserLoggedIn; else isLogOut">
                        <a class="nav-pnk" routerLink="/logout">Logout</a>
                  </span>

                  <ng-template #isLogOut>
                              <a class="nav-pnk" routerLink="/login">Login</a>
                  </ng-template>
      </p>
   </ul>
</span>

Open AppComponent and update below code −


import { Component } from  @angular/core ;

import { AuthService } from  ./auth.service ;

@Component({
   selector:  app-root ,
   templateUrl:  ./app.component.html ,
   styleUrls: [ ./app.component.css ]
})
export class AppComponent {

   title =  Expense Manager ;
   isUserLoggedIn = false;

   constructor(private authService: AuthService) {}

   ngOnInit() {
      let storeData = localStorage.getItem("isUserLoggedIn");
      console.log("StoreData: " + storeData);

      if( storeData != null && storeData == "true")
         this.isUserLoggedIn = true;
      else


         this.isUserLoggedIn = false;
   }
}

Here, we have added the logic to identify the user status so that we can show login / logout functionapty.

Open AppModule (src/app/app.module.ts) and configure ReactiveFormsModule


import { ReactiveFormsModule } from  @angular/forms ; 
imports: [ 
   ReactiveFormsModule 
]

Now, run the apppcation and the apppcation opens the login page.

ReactiveFormsModule

Enter admin and admin as username and password and then, cpck submit. The apppcation process the login and redirects the user to expense pst page as shown below −

FormsModule

Finally, your can cpck logout and exit the apppcation.

Advertisements