Spring Boot Regsiter And Login With Angular Part 2

Getting Started | Building an Application with Angular




In this tutorial we will be creating a register/Login and Logout page. We will be using a hard coded user name and password for authenticating a user. Also will be implementing session management so that only a used who is logged in can view the pages. Else he will be directed to the login page.


Create a new authentication service where we check if the user name and password is correct then set it in session storage. Using sessionStorage properties we can save key/value pairs in a web browser. The sessionStorage object stores data for only one session . So the data gets deleted if the browser is closed.

ng new

The Angular CLI makes it easy to create an application that already works, right out of the box. It already follows our best practices!


ng generate

Generate components, routes, services and pipes with a simple command. The CLI will also create simple test shells for all of these.


ng serve

Easily test your app locally while developing.


Open Command and tap this commands

 
   $  npm install -g @angular/cli 
$ ng new register-login
$ cd register-login
$ ng serve

We need to create three components

ng g c auth/register

ng g c auth/login

ng g c auth/profile



The next step We need to create two Services

ng g s auth/service/auth

ng g s auth/service/tokenStorage



The next step We need to create three Models

Create a new folder model in the auth folder inside it create three models

RegisterInfo.ts

LoginInfo.ts

ProfileInfo.ts



Install Angular Material & Routing Module

ng add @angular/material

ng generate module app-routing --flat --module=app



app.module.ts

       


import {BrowserModule} from '@angular/platform-browser'; import {NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import {AppComponent} from './app.component'; import {BrowserAnimationsModule } from '@angular/platform-browser/animations'; import {MatCardModule} from '@angular/material/card'; import {MatButtonModule } from '@angular/material/button'; import {MatInputModule} from '@angular/material/input'; import {MatSelectModule } from '@angular/material/select'; import {MatIconModule} from '@angular/material/icon'; import {FormsModule, ReactiveFormsModule } from '@angular/forms'; import {MatSliderModule} from '@angular/material/slider'; import {HttpClientModule } from '@angular/common/http'; import {MatProgressSpinnerModule} from '@angular/material/progress-spinner'; import {MatListModule } from '@angular/material/list'; import {MatProgressBarModule } from'@angular/material/progress-bar'; import {MatStepperModule} from '@angular/material/stepper'; import {MatRadioModule } from '@angular/material/radio'; import {MatFormFieldModule} from '@angular/material/form-field'; import {AppRoutingModule } from './app-routing.module'; import {RegisterComponent} from './auth/register/register.component'; import {LoginComponent } from './auth/login/login.component'; import {ProfileComponent} from './auth/profile/profile.component'; @NgModule({ declarations: [ AppComponent, ProfileComponent, RegisterComponent, LoginComponent ], imports: [ BrowserModule, BrowserAnimationsModule, BrowserModule, BrowserAnimationsModule, MatCardModule, MatButtonModule, MatInputModule, MatSelectModule, MatIconModule, ReactiveFormsModule, FormsModule, MatSliderModule, HttpClientModule, FormsModule, MatProgressSpinnerModule, MatListModule, MatProgressBarModule, MatStepperModule, MatRadioModule, MatFormFieldModule, AppRoutingModule ], schemas: [ CUSTOM_ELEMENTS_SCHEMA ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }

app.routing.module.ts

       


import {RegisterComponent} from './auth/register/register.component'; import {NgModule } from '@angular/core'; import {Routes, RouterModule} from '@angular/router'; import {LoginComponent } from './auth/login/login.component'; import {ProfileComponent} from './auth/profile/profile.component'; const routes: Routes = [ { path: '', redirectTo: '/login', pathMatch: 'full' }, { path: 'login', component: LoginComponent }, { path: 'register', component: RegisterComponent }, { path: 'profile/:username', component: ProfileComponent } ]; @NgModule({ imports: [RouterModule. forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }

LoginInfo.ts

       


export class LoginInfo { username: string; password: string; constructor(username: string, password: string) { this.username = username; this.password = password; } }

RegisterInfo.ts

       

export class RegisterInfo { name: string; username: string; email: string; password: string; gender: string; birthDate: any; createAt: any; role: string[]; constructor(name: string, username: string, email: string, password: string, gender: string, birthDate: any, createAt: any) { this.name = name; this.username = username; this.email = email; this.password = password; this.gender = gender; this.birthDate = birthDate; this.createAt = createAt; this.role = ['user']; } }

ProfileInfo.ts

       

export class ProfileInfo { id: number; name: string; username: string; email: string; password: string; gender: string; birthDate: any; createAt: any; }

auth.service.ts

       

import {Injectable } from '@angular/core'; import {HttpClient, HttpHeaders} from '@angular/common/http'; import {Observable } from 'rxjs'; import {LoginInfo} from '../model/LoginInfo'; import {RegisterInfo } from '../model/RegisterInfo'; const httpOptions = { headers: new HttpHeaders({'content-Type': 'application/json'}) }; @Injectable({ providedIn: 'root' }) export class AuthService { constructor(private http: HttpClient) {} private urlAuth = 'http://localhost:8080/api/auth'; login(info: LoginInfo): Observable<any> { return this.http.post<any>(this.urlAuth + '/login', info, httpOptions); } register(info: RegisterInfo): Observable<RegisterInfo> { return this.http.post<RegisterInfo>(this.urlAuth + '/register', info, httpOptions); } getUserByUsername(username: string): Observable<any> { return this.http.get<any>(this.urlAuth + `/getUserByUsername/${username}`); } findUserById(id: number): Observable<any> { return this.http.get<any>(this.urlAuth + `/findUserById/${id}`); } updateUser(user: any, id: number): Observable<any> { return this.http.put<any>(this.urlAuth + `/updateUser/${id}`, user); } deleteUser(id: number): any { this.http.delete(this.urlAuth + `/deleteUser/${id}`, { responseType: 'text' }); } findAllUsers(): Observable<RegisterInfo[]> { return this.http.get<RegisterInfo[]>(this.urlAuth + `/findAllUsers`); } }

token-storage.service.ts

       

import {Injectable } from '@angular/core'; const TOKEN_KEY = 'AuthToken'; const USERNAME_KEY = 'AuthUsername'; const AUTHORITIES_KEY = 'AuthAuthorities'; const NAME_KEY = 'AuthName'; const EMAIL_KEY = 'AuthEmail'; @Injectable({ providedIn: 'root' }) export class TokenStorageService { private roles: Array<string> = []; public signOut(): void { window.sessionStorage.clear(); } public saveToken(token: string): void { window.sessionStorage.removeItem(TOKEN_KEY); window.sessionStorage.setItem(TOKEN_KEY, token); } public getToken(): string { return sessionStorage.getItem(TOKEN_KEY); } public saveUsername(username: string): void { window.sessionStorage.removeItem(USERNAME_KEY); window.sessionStorage.setItem(USERNAME_KEY, username); } public getUsername(): string { return sessionStorage.getItem(USERNAME_KEY); } public saveName(name: string): void { window.sessionStorage.removeItem(NAME_KEY); window.sessionStorage.setItem(NAME_KEY, name); } public getName(): string { return sessionStorage.getItem(NAME_KEY); } public saveEmail(email: string): void { window.sessionStorage.removeItem(EMAIL_KEY); window.sessionStorage.setItem(EMAIL_KEY, email); } public getEmail(): string { return sessionStorage.getItem(EMAIL_KEY); } public saveAuthorities(authorities: string[]): void { window.sessionStorage.removeItem(AUTHORITIES_KEY); window.sessionStorage.setItem(AUTHORITIES_KEY, JSON.stringify(authorities)); } public getAuthorities(): string[] { this.roles = []; if (sessionStorage.getItem(TOKEN_KEY)) { JSON.parse(sessionStorage.getItem(AUTHORITIES_KEY)).forEach(authority => { this.roles. push(authority.authority); }); } return this.roles; } }

register.component.ts

            

import {Component, OnInit} from '@angular/core'; import {Router } from '@angular/router'; import {LoginInfo} from '../model/LoginInfo'; import {RegisterInfo } from '../model/RegisterInfo'; import {AuthService} from '../service/auth.service'; import {TokenStorageService } from '../service/token-storage.service'; @Component({ selector: 'app-register', templateUrl: './register.component.html', styleUrls: ['./register.component.css'] }) export class RegisterComponent implements OnInit { form: any = {}; isSignedUp = false; signUpInfo: RegisterInfo; showSpinner = false; isSignUpFailed = false; errorMessage = false; gender: any = {}; roles: string[] = []; loginInfo: LoginInfo; profileInfo: RegisterInfo[]; constructor(private authService: AuthService, private router: Router, private tokenStorageService: TokenStorageService) { } ngOnInit(): void { this.gender = 'female'; } setGender(): void { this.form.gender = this.gender; } onSubmit(): void { this.showSpinner = true; this.signUpInfo = new RegisterInfo( this.form.name, this.form.username, this.form.email, this.form.password, this.form.gender, this.form.birthDate, this.form.createdAt, ); this.signUpInfo.role = ['admin']; this.authService.register(this.signUpInfo).subscribe(signUpInfo => { this.signUpInfo = signUpInfo; this.loginInfo = new LoginInfo( this.form.username, this.form.password ); this.authService.login(this.loginInfo).subscribe(loginInfo => { this.tokenStorageService.saveToken(loginInfo.accessToken); this.tokenStorageService.saveUsername(loginInfo.username); this.tokenStorageService.saveAuthorities(loginInfo.authorities); this.roles = this.tokenStorageService.getAuthorities(); this.isSignedUp = true; this.showSpinner = false; this.isSignedUp = true; this.isSignUpFailed = false; this.router.navigate(['/profile/' + this.form.username]); }); }, error => { this.errorMessage = error.error.message; this.isSignUpFailed = true; }); } reset(): void { this.form.name = ''; this.form.username = ''; this.form.email = ''; this.form.password = ''; this.form.gender = ''; this.form.birthDate = ''; this.form.createAt = ''; } }

register.component.html

       

<div class="content"> <br> <mat-card class="example-card" style="background: blanchedalmond;"> <mat-card-header style="background: #d35400; padding: 15px 10px 6px; color: #000fff; border-radius: 5px"> <mat-card-title> <mat-icon>how_to_reg</mat-icon> <span style="margin-left: 8px">Register</span> </mat-card-title> </mat-card-header> <mat-card-content> <mat-list> <mat-list-item>Please fill the fields</mat-list-item> <mat-divider></mat-divider> </mat-list> <mat-progress-bar mode="indeterminate" *ngIf="showSpinner"> </mat-progress-bar> <form (ngSubmit)="formRegister.form.valid && onSubmit() " #formRegister="ngForm" novalidate> <mat-vertical-stepper linear style="background: blanchedalmond;"> <mat-step label="Step 1"> <mat-form-field> <mat-label>Username</mat-label> <input type="text" matInput placeholder="username" name="username" #username="ngModel" [(ngModel)]="form.username"> </mat-form-field> <br> <mat-form-field> <mat-label>Email</mat-label> <input type="text" matInput placeholder="email" name="email" #email="ngModel" [(ngModel)]="form.email"> </mat-form-field> <br> <mat-form-field> <mat-label>Password</mat-label> <input type="password" matInput placeholder="password" name="password" #password="ngModel" [(ngModel)]="form.password"> </mat-form-field> <br> </mat-step> <mat-step label="Step 2"> <mat-form-field> <mat-label>Name</mat-label> <input type="text" matInput placeholder="name" name="name" #name="ngModel" [(ngModel)]="form.name"> </mat-form-field> <br> <mat-form-field > <mat-label>Birth date</mat-label> <input type="date" matInput placeholder="Birth Date" name="birthDate" #birthDate="ngModel" [(ngModel)]="form.birthDate"> </mat-form-field> <br> <div style="margin-bottom: 10px;"> <strong>Gender</strong> </div> <mat-radio-group aria-label="Select an option" [(ngModel)]="gender" name="gender" (ngModelChange)="setGender()"> <mat-radio-button value="female">Female</mat-radio-button> <mat-radio-button value="male" style="margin-left: 10px;">Male</mat-radio-button> </mat-radio-group> <div style="margin-top: 15px"> <button mat-raised-button color="accent" type="submit" [disabled]="username.invalid || email.invalid || password.invalid || name.invalid || birthDate.invalid" > Register <mat-icon>supervisor_account</mat-icon> </button> <button mat-button matStepperPrevious>Back </button> <button mat-button (click)="reset()">Reset </button> </div> </mat-step> </mat-vertical-stepper> </form> </mat-card-content> <hr> <mat-card-actions> <p style="margin-left: 10px; float: right">All ready i have an account <button mat-button color="primary" routerLink="/login"> Login<mat-icon>exit_to_app</mat-icon> </button> </p> </mat-card-actions> </mat-card> </div>

register.component.css

       

.content { display: flex; margin: 82px auto 32px; padding: 0 16px; max-width: 960px; flex-direction: column; align-items: center; } mat-card { width: 600px; } mat-form-field { width: 300px; } .alert { padding: 4px 20px; background-color: #1abc9c; color: white; border-radius: 6px; margin-top: 30px; }

login.component.ts

       

import {Component, OnInit } from '@angular/core'; import {Router } from '@angular/router'; import {LoginInfo } from '../model/LoginInfo'; import {AuthService } from '../service/auth.service'; import {TokenStorageService } from '../service/token-storage.service'; @Component({ selector: 'app-login', templateUrl: './login.component.html', styleUrls: ['./login.component.css'] }) export class LoginComponent implements OnInit { form: any = {}; isLoggedIn = false; isLoginFailed = false; loginInfo: LoginInfo; showSpinner = false; constructor(private authService: AuthService, private router: Router, private tokenStorageService: TokenStorageService) { } ngOnInit(): void { } onSubmit(): void { this.showSpinner = true; this.loginInfo = new LoginInfo( this.form.username, this.form.password ); this.authService.login(this.loginInfo).subscribe(data => { this.tokenStorageService.saveToken(data.accessToken); this.tokenStorageService.saveUsername(data.username); this.tokenStorageService.saveAuthorities(data.authorities); this.isLoggedIn = true; this.isLoginFailed = false; this.router.navigate(['/profile/' + this.form.username]); }, error => { this.isLoginFailed = true; this.showSpinner = false; }); } }

login.component.html

       

<div *ngIf='isLoggedIn; else loggedOut' > <app-home></app-home> </div> <ng-template #loggedOut> <div class="content"> <div *ngIf="isLoginFailed" class="alert"> <p> Username or password not correct </p> </div> <mat-card style="background: blanchedalmond;"> <mat-card-header> <mat-card-title>Login</mat-card-title> <mat-card-subtitle>Please fill the fields</mat-card-subtitle> </mat-card-header> <mat-card-content> <mat-spinner [diameter]="34" *ngIf="showSpinner"></mat-spinner> <form (ngSubmit)="formLogin.form.valid && onSubmit() " #formLogin="ngForm" novalidate> <mat-form-field> <mat-label>Username</mat-label> <input type="text" matInput placeholder="username" name="username" #username="ngModel" [(ngModel)]="form.username"> </mat-form-field> <br> <mat-form-field> <mat-label>Password</mat-label> <input type="password" matInput placeholder="password" name="password" #password="ngModel" [(ngModel)]="form.password"> </mat-form-field> <br> <button mat-raised-button color="accent" type="submit" > Login<mat-icon>exit_to_app</mat-icon> </button> </form> </mat-card-content> <mat-card-actions> <p style="margin-left: 10px">I don't have an account <button mat-button color="primary" routerLink="/register">Register <mat-icon> supervisor_account </mat-icon> </button> </p> </mat-card-actions> </mat-card> </div> </ng-template>

login.component.css

       

.content { display: flex; margin: 82px auto 32px; padding: 0 16px; max-width: 960px; flex-direction: column; align-items: center; } mat-card { width: 320px; } mat-form-field { width: 300px; } .alert { padding: 4px 20px; background-color: #c0392b; color: white; border-radius: 6px; margin-top: 20px; }

profile.component.ts

       

import {RegisterInfo } from './../model/RegisterInfo'; import {Component, OnInit } from '@angular/core'; import {ActivatedRoute, Router } from '@angular/router'; import {AuthService } from '../service/auth.service'; import {TokenStorageService } from '../service/token-storage.service'; import {ProfileInfo } from '../model/ProfileInfo'; @Component({ selector: 'app-profile', templateUrl: './profile.component.html', styleUrls: ['./profile.component.css'] }) export class ProfileComponent implements OnInit { username = ''; profileInfo: ProfileInfo = {} as ProfileInfo; constructor(private authService: AuthService, private router: Router, private route: ActivatedRoute, private tokenService: TokenStorageService) { } ngOnInit(): void { this.username = this.route.snapshot.params.username; this.authService.getUserByUsername(this.username).subscribe(info => { this.profileInfo = info; console.log(this.profileInfo); }); } logout(): void { this.tokenService.signOut(); this.router.navigateByUrl('/'); } }

profile.component.html

       

<div class="content"> <mat-card> <mat-card-header style="background: #d35400; padding: 15px 10px 6px; color: #000fff; border-radius: 5px"> <mat-card-title> <mat-icon>supervisor_account</mat-icon> Your profile</mat-card-title> </mat-card-header> <mat-card-content> <mat-list> <mat-list-item>Username: {{profileInfo.username}} </mat-list-item> <mat-divider></mat-divider> <mat-list-item>Email: {{profileInfo.email}} </mat-list-item> <mat-divider></mat-divider> <mat-list-item>Name: {{profileInfo.name}} </mat-list-item> <mat-divider></mat-divider> <mat-list-item>Birth date: {{profileInfo.birthDate | date}} </mat-list-item> <mat-divider></mat-divider> <mat-list-item>Gender: {{profileInfo.gender}} </mat-list-item> <mat-divider></mat-divider> <mat-list-item>Created At: {{profileInfo.createAt | date}} </mat-list-item> <mat-divider></mat-divider> </mat-list> </mat-card-content> <mat-card-actions> <button mat-raised-button color="accent" (click)="logout()">Logout <mat-icon>arrow_forward</mat-icon></button> </mat-card-actions> </mat-card> </div>

profile.component.css

       
.content { display: flex; margin: 82px auto 32px; padding: 0 16px; max-width: 960px; flex-direction: column; align-items: center; }

Now Run Application

ng serve


Conclusion

Now we have an overview of Spring Boot CRUD example when building a CRUD App and Config, JWT for secuirty

We also take a look at client-server architecture for REST API using Spring Web MVC & Spring Data JPA, as well, we are gooing to continue with Angular 10 project structure for building a front-end app to make HTTP requests and consume responses.



Post a Comment

Previous Post Next Post


Follow us on facebook