Authentication is the process matching the visitor of a web application with the pre-defined set of user identity in the system. In other word, it is the process of recognizing the users 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 authorized to access a resource.
Let us learn how to do Authentication and Authorization in Angular application in this tutorial.
Guards in Routing
In a web application, 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 unauthorized access to certain part of the application 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 replies in negative.
Resolve: Used to pre-fetch the data before navigating to the route.
CanLoad: Used to load assets.
Working Example
In this example, we are going to add login and logout functionality to an angular application and secure it using CanActivate guard. Follow the given steps:
Step 1: Create an angular application using the following command −
ng newnew-app
Step 2: Now, navigate to project root folder.
cd new-app
Step 3: Next, we include the Bootstrap into our new-app application using styles option and change the default template to use Bootstrap components. Use the below command to install Bootstrap and JQuery in the project −
npm install --save bootstrap jquery
Now, open angular.json file and set bootstrap and jquery library path −
scripts option is used to include JavaScript library.
Step 4: Create a new service named AuthService to authenticate the user. The command given below will create a service with the name auth inside Services folder.
ng generate service Services/auth
On successful creation of service, you may see the below output on Angular CLI −
import{ Injectable }from'@angular/core';import{ Observable,of, BehaviorSubject }from'rxjs';import{ tap, delay }from'rxjs/operators';
@Injectable({
providedIn:'root'})exportclassAuthService{// Track login state with BehaviorSubjectprivate isUserLoggedInSubject =newBehaviorSubject<boolean>(false);constructor(){// Only initialize sessionStorage on the client-side (browser)if(typeof window !=='undefined'&& window.sessionStorage){const storedLoginState = sessionStorage.getItem('isUserLoggedIn')==='true';this.isUserLoggedInSubject.next(storedLoginState);}}login(userName: string, password: string): Observable<boolean>{const isLoggedIn = userName ==='admin'&& password ==='admin';if(typeof window !=='undefined'&& window.sessionStorage){
sessionStorage.setItem('isUserLoggedIn', isLoggedIn ?'true':'false');}// Update the BehaviorSubject with new login statethis.isUserLoggedInSubject.next(isLoggedIn);returnof(isLoggedIn).pipe(delay(1000),tap(val=> console.log("Is User Authentication successful: "+ val)));}logout():void{if(typeof window !=='undefined'&& window.sessionStorage){
sessionStorage.removeItem('isUserLoggedIn');}// Update the BehaviorSubject to false when logged outthis.isUserLoggedInSubject.next(false);}// Expose the login status as an observablegetisUserLoggedIn$(): Observable<boolean>{returnthis.isUserLoggedInSubject.asObservable();}}</pre>
Here,
We have written two methods, login and logout.
The purpose of the login method is to validate the user and if the user successfully validated, it stores the information in localStorage and then returns true.
Authentication validation 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 invalidate the user and removes the information stored in localStorage.
Step 6: Create a login component using below command −
ng generate component login
Following output will be produced on running the above code −
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): boolean | UrlTree {let url: string = state.url;returnthis.checkLogin(url);}checkLogin(url: string):true| UrlTree {
console.log("Url: "+ url);// Check if sessionStorage is available (only in the browser)if(typeof window !=='undefined'&& window.sessionStorage){let val = sessionStorage.getItem('isUserLoggedIn');// Check if the value is 'true'if(val ==="true"&& val !=null){// If the user is already logged in and trying to access the login page, redirect to /expensesif(url ==="/login"){returnthis.router.parseUrl('/expenses');}else{returntrue;// User is allowed to proceed}}else{// If the user is not logged in, redirect to /loginreturnthis.router.parseUrl('/login');}}// In case sessionStorage isn't available (for SSR)returnthis.router.parseUrl('/login');}}</pre>
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.
Step 14: Let's add a new component in our application. User will be redirected to this page on successful login.
Here, the command creates the ExpenseEntryList Component and add the necessary code by default.
Step 15: Create a ExpenseEntry interface within src/app/expense-entry-list.component.ts file. Then, add a method named getExpenseEntries() to return list of expense entry (mock items) in ExpenseEntryListComponent. Also, declare a local variable, expenseEntries and load the mock list of expense entries.
title ='Angular Authentication';
isUserLoggedIn: any =false;
router: any;constructor(private authService: AuthService){}ngOnInit(){// Subscribe to the isUserLoggedIn observable from AuthServicethis.authService.isUserLoggedIn$.subscribe(status=>{this.isUserLoggedIn = status;
console.log("Is User Logged In: ",this.isUserLoggedIn);});}logout():void{// Trigger logout in AuthServicethis.authService.logout();// Redirect to the homepage after logoutthis.router.navigate(['/']);}}</pre>
Here, we have added the logic to identify the user status so that we can show login/logout functionality.
Step 20: Start the application using following command −
ng serve
Enter admin as username and password and then, click submit. The application process the login and redirects the user to expense list page as shown below −