DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • Create a Multi-Tenancy Application in Nest.js, Part 4: Authentication and Authorization Setup
  • Difference Between Bootstrap and AngularJS in 2022
  • The Best Javascript Frameworks for 2022
  • Achieving Micro-frontend Architecture Using Angular Elements

Trending

  • Efficient API Communication With Spring WebClient
  • How To Introduce a New API Quickly Using Quarkus and ChatGPT
  • The Evolution of Scalable and Resilient Container Infrastructure
  • Supervised Fine-Tuning (SFT) on VLMs: From Pre-trained Checkpoints To Tuned Models
  1. DZone
  2. Coding
  3. Frameworks
  4. Implementing Guard in Angular 5 App

Implementing Guard in Angular 5 App

Allowing users to log in and log out, and base their permissions on this, is a crucial piece of web app security. Learn how to implement it with Angular 5!

By 
Sibeesh Venu user avatar
Sibeesh Venu
·
Apr. 05, 18 · Tutorial
Likes (17)
Comment
Save
Tweet
Share
71.5K Views

Join the DZone community and get the full member experience.

Join For Free

Introduction

This post is a continuation of the Developing an Angular 5 App series, if you haven't gone through the previous posts yet, I strongly recommend you to do that. You can find the links to the previous posts below. In this post, we are going to implement Guard, which helps us to restrict a user's access to pages if they haven't logged in to our application. So, at the end of this article, you will know how you can handle unauthorized route access attempts. I hope you will like this article.

'Developing an Angular 5 App' Series

These are the previous posts in this series. Please go ahead and have a look.

  1. What Is New and How to Set Up our First Angular 5 Application
  2. Angular 5 Basic Demo Project Overview
  3. Generating Your First Components And Modules in Angular 5 App
  4. Implement Validations in Angular 5 App
  5. Implementing Guard in Angular 5 App

You can always clone or download the source code here.

Background

We may have any number of pages in our app, some of which may be used only by users who are logged in, and some may be used by unauthorized users. But, are you letting all users access all the pages in the app, whether they have logged in or not? Yeah, obviously that's not a perfect application. In our application, we are going to make our homepage available only for a logged in user. To do this, we can use Guard.

Using the Code

Let's go ahead and write some code now.

Generate Guard

As we are using Angular CLI, we can easily generate Auth Guard in our application. Do you remember how we created components in our previous articles? We can create a Guard in the same way.

PS F:\Visual Studio\ng5> ng generate guard auth

In the above step, we are generating Guard on our root level. Once you run the above command, this will generate two new TypeScript files, as follows.

Let's go to those two files now.

auth.guard.ts

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

@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    return true;
  }
}

auth.guard.spec.ts

import { TestBed, async, inject } from '@angular/core/testing';

import { AuthGuard } from './auth.guard';

describe('AuthGuard', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [AuthGuard]
    });
  });

  it('should ...', inject([AuthGuard], (guard: AuthGuard) => {
    expect(guard).toBeTruthy();
  }));
});

This is just a test file, we can see how to perform tests on the Angular app in another article. Let's concentrate on the implementation for now.

Generate a Login Component and Set it Up

Now that we have Guard ready for modification, before we dive into the modificaitn, let's create a component for logging in.

PS F:\Visual Studio\ng5> ng g c login
  create src/app/login/login.component.html (24 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 (1331 bytes)
PS F:\Visual Studio\ng5>

Now it is time to edit our routes in app.module.ts with the new route for logging in. Please note that it is not a recommended way to create routes in an app.module.ts file. We should create a separate routing module for that route and use it in app.module.ts. I will be sharing how to do that in another article.

import { LoginComponent } from './login/login.component';

const myRoots: Routes = [
  { path: '', component: HomeComponent, pathMatch: 'full' },
  { path: 'register', component: RegistrationComponent },
  { path: 'login', component: LoginComponent},
  { path: 'home', component: HomeComponent}]

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    NavComponent,
    RegistrationComponent,
    LoginComponent
  ],
  imports: [
    BrowserModule, BrowserAnimationsModule, FormsModule, ReactiveFormsModule,
    MatButtonModule, MatCardModule, MatInputModule, MatSnackBarModule, MatToolbarModule,
    RouterModule.forRoot(myRoots)
  ],
  providers: [],
  bootstrap: [AppComponent]
})

We may also need to edit the nav.component.html file by adding a new button for logging in.

<mat-toolbar color="primary">
  <button mat-button routerLink="/">Home</button>
  <button mat-button routerLink="/register">Register</button>
  <button mat-button routerLink="/login">Login</button>
</mat-toolbar>

Now, go to your login.component.html file and add the following markup.

<mat-card>
  <form [formGroup]="form" (ngSubmit)="login()">
    <mat-input-container>
      <input matInput type="email" placeholder="Email" formControlName="email" />
    </mat-input-container>
    <mat-input-container>
      <input matInput type="password" placeholder="Password" formControlName="password" />
    </mat-input-container>
    <button mat-raised-button type="submit" color="primary">Login</button>
  </form>
</mat-card>

As you can see, we are actually calling a login method when the butto is clicked. Before we implement that function, in our login.component.ts file let's create an auth service and edit it as follows.

import { Injectable } from '@angular/core';
import { Router } from '@angular/router';

@Injectable()
export class AuthService {

  constructor(private myRoute: Router) { }

  sendToken(token: string) {
    localStorage.setItem("LoggedInUser", token)
  }

  getToken() {
    return localStorage.getItem("LoggedInUser")
  }

  isLoggednIn() {
    return this.getToken() !== null;
  }

  logout() {
    localStorage.removeItem("LoggedInUser");
    this.myRoute.navigate(["login"]);
  }


}

Now it is time to edit our login.component.ts file.

import { Component, OnInit } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { AuthService } from '../auth.service';

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

  form;
  constructor(private fb: FormBuilder,
    private myRoute: Router,
    private auth: AuthService) {
    this.form = fb.group({
      email: ['', [Validators.required, Validators.email]],
      password: ['', Validators.required]
    });
  }

  ngOnInit() {
  }

  login() {
    if (this.form.valid) {
      this.auth.sendToken(this.form.value.email)
      this.myRoute.navigate(["home"]);
    }
  }

}

This is not the preferred way of doing this, instead, you should create an API service and connect to a database. And then, check whether this email and password are valid or not, and, lastly, you should set localStorage with the token you get from the server's API. This topic is enough for another article, to make this article managable, I am just setting the value email here.

If you are getting an error like, "ERROR Error: Uncaught (in promise): EmptyError: no elements in sequence," please make sure that you have an rxjs version greater than or equal to 5.5.4 in the package.json file. The rxjs version 5.5.3 has this issue with Angular 5.

Now run your application and make sure that it is redirecting to the homepage. You can also check the localStorage entry on your browser console.

Set Up Guard Generated

Let's go to our auth.guard.ts file and make some changes.

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { AuthService } from './auth.service';
import {Router} from '@angular/router';

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private auth: AuthService,
    private myRoute: Router){

  }

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    if(this.auth.isLoggednIn()){
      return true;
    }else{
      this.myRoute.navigate(["login"]);
      return false;
    }
  }
}

Do not forget to add AuthService and AuthGuard as providers in app.module.ts.

import { AuthService } from './auth.service';
import { AuthGuard } from './auth.guard';

Use Auth Guard in Routes

Wow, the set up is done, now it is time for action. Let's go to our routes now and change the code as follows:

const myRoots: Routes = [
  { path: '', component: HomeComponent, pathMatch: 'full' , canActivate: [AuthGuard]},
  { path: 'register', component: RegistrationComponent },
  { path: 'login', component: LoginComponent},
  { path: 'home', component: HomeComponent, canActivate: [AuthGuard]}
];

Run your application and try to access the home page before logging in. If everything goes fine, it should redirect you to login page.

Let's do some more coding in the nav.component.html and nav.component.ts files to make our app more meaningful.

nav.component.ts

import { Component, OnInit } from '@angular/core';
import { AuthService } from '../auth.service';

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

  constructor(private auth: AuthService) { }

  ngOnInit() {
  }

}

nav.component.html

<mat-toolbar color="primary">
  <button mat-button routerLink="/home">Home</button>
  <button mat-button *ngIf="!auth.isLoggednIn()" routerLink="/register">Register</button>
  <button mat-button *ngIf="!auth.isLoggednIn()" routerLink="/login">Login</button>
  <button mat-button *ngIf="auth.isLoggednIn()" (click)="auth.logout()">Logout</button>
</mat-toolbar>

Here we are just making the log out button available only for logged in users and hiding the register and login buttons for logged in users. Sounds good, right? The auth.isLoggedIn function will be available on this page as we are injecting the auth service in out nav.component.ts file.

Thanks a lot for reading. Did I miss anything that you think is needed? Did you find this post useful? I hope you liked this article. Please share your valuable suggestions and feedback.

app Guard (information security) AngularJS application

Published at DZone with permission of Sibeesh Venu, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Create a Multi-Tenancy Application in Nest.js, Part 4: Authentication and Authorization Setup
  • Difference Between Bootstrap and AngularJS in 2022
  • The Best Javascript Frameworks for 2022
  • Achieving Micro-frontend Architecture Using Angular Elements

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!