Authentication in Angular 6


Create new MongoDB database named learn_angular_5. This database have 1 collection: Account collection

/* Create learn_angular_5 database */
use learn_angular_5

/* Create Account collection */
db.createCollection('account');

/* Dumping data for `account` collection */
/* 1 */
{
    "_id" : ObjectId("5a7dbb28cc5142b4bd403efd"),
    "username" : "acc1",
    "password" : "123",
    "fullName" : "Account 1"
}

/* 2 */
{
    "_id" : ObjectId("5a7dbb40cc5142b4bd403f08"),
    "username" : "acc2",
    "password" : "123",
    "fullName" : "Account 2"
}

/* 3 */
{
    "_id" : ObjectId("5a7dbb56cc5142b4bd403f11"),
    "username" : "acc3",
    "password" : "123",
    "fullName" : "Account 3"
}

Create LearnAngular5withRealApps_Server folder and select to this folder in Visual Studio Code

Use the following command to install Mongoose:

npm install mongoose --save

Use the following command to install Express.JS:

npm install express --save
npm install body-parser --save
npm install cookie-parser --save
npm install multer --save




Create schemas folder in Node project. Create account.schema.js file into schemas folder. Declare schema for account collection as below:

var mongoose = require('mongoose');

var AccountSchema = new mongoose.Schema(
    {
        username: String,
        password: String,
        fullName: String
    },
    {
        versionKey: false
    }
);

module.exports = mongoose.model('Account', AccountSchema, 'account');

Create a new folder named api inside the server project. Create account.api.js file inside api folder contains Rest APIs login with username and password from client

var mongoose = require('mongoose');
var Account = require('../schemas/account.schema');

var AccountAPI = {

    login: function (request, response) {

        Account.find()
                .where('username').equals(request.body.username)
                .where('password').equals(request.body.password)
                .count(function(error, numRows) {
                    response.status(200).json({
                        count: numRows
                    });
                });
    }

};

module.exports = AccountAPI;

Inside the api folder create a new file named index.js. This file will hold all the routes needed for rest api in server.

var express = require('express');
var mongoose = require('mongoose');

var router = express.Router();

mongoose.connect('mongodb://localhost:27017/learn_angular_5');

var AccountAPI = require('./account.api');

router.post('/account/login', AccountAPI.login);

module.exports = router;




At the root of server project, create a file named server.js. This will be the entry point into node application. This will start the server and listen on a local port

var express = require('express');
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.urlencoded({
	extended: true
}));
app.use(bodyParser.json());

app.all('/*', function (req, res, next) {
	res.header("Access-Control-Allow-Origin", "*");
	res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
	res.header('Access-Control-Allow-Headers', 'Content-type,Accept,X-Access-Token,X-Key');
	if (req.method == 'OPTIONS') {
		res.status(200).end();
	} else {
		next();
	}
});

app.use('/api', require('./api/index'));

var server = app.listen(9090, function () {
	var host = server.address().address;
	var port = server.address().port;
	console.log("Server listening at http://%s:%s", host, port)
});

At the root of server project run command: node server.js

Create new folder named learnangular5withrealapps and select to this folder in Visual Studio Code

Open Terminal windows in Visual Studio Code and type: npm install -g @angular/cli to install Angular 6

Create new folder, named services in src\app folder. In this folder, create new services class as below:

In src\app\services folder, create new TypeScript file, named account.service.ts

import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Rx';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';

@Injectable()
export class AccountService {

    BASE_URL: string = 'http://localhost:9090/api/account/';
    private loggedIn = false;

    constructor(
        private http: Http
    ) { }

    login(username: string, password: string): Observable<any> {
        return this.http.post(this.BASE_URL + 'login', { username: username, password: password })
            .map((res: Response) => {
                var result = res.json();
                this.loggedIn = result.count == 1;
                return { status: res.status, data: result };
            })
            .catch((error: any) => {
                return Observable.throw(new Error(error.status))
            });
    }

    logout(): void {
        this.loggedIn = false;
    }

    isLoggedIn(): boolean {
        return this.loggedIn;
    }

}




In src\app\services folder, create new TypeScript file, named dashboardguard.service.ts

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { AccountService } from './account.service';

@Injectable()
export class DashboardGuard implements CanActivate {

    constructor(
        private accountService: AccountService,
        private router: Router
    ) { }

    canActivate() {
        if (this.accountService.isLoggedIn()) {
            return true;
        }
        this.router.navigate(['/login']);
        return false;
    }

}

Create new folder, named components in src\app folder. In this folder, create children components as below:

Create new folder named home in src\app\components folder. In this folder, create new TypeScript file named home.component.ts

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

@Component({
    templateUrl: 'index.component.html'
})

export class HomeComponent implements OnInit {

    ngOnInit() {
    }

}

Create new file, named index.component.html contains html for home page

<h3>Home Page</h3>

Create new folder named login in src\app\components folder. In this folder, create new TypeScript file named login.component.ts

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { Router } from '@angular/router';
import { AccountService } from '../../services/account.service';

@Component({
    templateUrl: 'index.component.html'
})

export class LoginComponent implements OnInit {

    loginForm: FormGroup;
    errorMsg: string = '';

    constructor(
        private formBuilder: FormBuilder,
        private accountService: AccountService,
        private router: Router
    ) { }

    ngOnInit() {
        this.loginForm = this.formBuilder.group({
            username: '',
            password: ''
        });
    }

    login(): void {
        this.accountService.login(this.loginForm.value
            .username, this.loginForm.value.password).subscribe(
                res => {
                    if (res.data.count == 1) {
                        this.errorMsg = '';
                        localStorage.setItem('auth_token', this.loginForm.value
                            .username);
                        this.router.navigate(['/dashboard']);
                    } else {
                        this.errorMsg = 'Invalid Account';
                    }
                },
                error => {
                    this.errorMsg = error.message;
                }
            );
    }

}

Create new file, named index.component.html contains html for login page

<h3>Login</h3>
<form [formGroup]="loginForm" (ngSubmit)="login()">
    {{errorMsg}}
    <table>
        <tr>
            <td>Username</td>
            <td>
                <input type="text" formControlName="username">
            </td>
        </tr>
        <tr>
            <td>Password</td>
            <td>
                <input type="password" formControlName="password">
            </td>
        </tr>
        <tr>
            <td>&nbsp;</td>
            <td>
                <input type="submit" value="Login">
            </td>
        </tr>
    </table>
</form>




Create new folder named logout in src\app\components folder. In this folder, create new TypeScript file named logout.component.ts

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { AccountService } from '../../services/account.service';

@Component({
    templateUrl: 'index.component.html'
})

export class LogoutComponent implements OnInit {

    constructor(
        private accountService: AccountService,
        private router: Router
    ) { }

    ngOnInit() {
        localStorage.removeItem('auth_token');
        this.accountService.logout();
        this.router.navigate(['/login']);
    }

}

Create new file, named index.component.html contains html for logout page

<h3>Logout Page</h3>

Create new folder named dashboard in src\app\components folder. In this folder, create new TypeScript file named dashboard.component.ts

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

@Component({
    templateUrl: 'index.component.html'
})

export class DashboardComponent implements OnInit {

    ngOnInit() {
    }

}

Create new file, named index.component.html contains html for dashboard page

<h3>Welcome to Dashboard</h3>

Create new TypeScript file, named app.routing.ts in src\app folder. This file contains routes of urls in template

import { Routes, RouterModule } from '@angular/router';

import { DashboardComponent } from './components/dashboard/dashboard.component';
import { HomeComponent } from './components/home/home.component';
import { LoginComponent } from './components/login/login.component';
import { LogoutComponent } from './components/logout/logout.component';

import { DashboardGuard } from './services/dashboardguard.service';

const routes: Routes = [
	{ path: '', component: HomeComponent },
	{ path: 'login', component: LoginComponent },
	{ path: 'dashboard', component: DashboardComponent, canActivate: [DashboardGuard] },
	{ path: 'logout', component: LogoutComponent },
	{ path: '**', redirectTo: '' }
];

export const routing = RouterModule.forRoot(routes);

Create new TypeScript file, named app.component.ts in src\app folder.

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

@Component({
    selector: 'app-root',
    templateUrl: 'app.component.html'
})

export class AppComponent implements OnInit {

    ngOnInit() {
    }

}




Create new file, named app.component.html in src\app folder.

<a [routerLink]="['/']">Home</a> |
<a [routerLink]="['/login']">Login</a> |
<a [routerLink]="['/dashboard']">Dashboard</a> |
<a [routerLink]="['/logout']">Logout</a>
<br><br>
<router-outlet></router-outlet>

In app.module.ts file in src\app folder. Add new components and new services to module

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';
import { DashboardComponent } from './components/dashboard/dashboard.component';
import { HomeComponent } from './components/home/home.component';
import { LoginComponent } from './components/login/login.component';
import { LogoutComponent } from './components/logout/logout.component';

import { AccountService } from './services/account.service';
import { DashboardGuard } from './services/dashboardguard.service';

import { routing } from './app.routing';

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    DashboardComponent,
    LoginComponent,
    LogoutComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    ReactiveFormsModule,
    HttpModule,
    routing
  ],
  providers: [
    AccountService,
    DashboardGuard
  ],
  bootstrap: [AppComponent]
})

export class AppModule { }

In Terminal windows in Visual Studio Code and type: ng serve –open, program will open url http://localhost:4200/ on browser




If you have not logged in, you will be redirected to the login page

If you login successfully will open the dashboard page

I recommend you refer to the books below to learn more about the knowledge in this article: