Securing Angular 7 application with Spring Boot Basic Security

We need to configure users and their roles in in separate configuration file. We are creating two projects here –

In this article , i will take you through all the steps to secure your angular application with spring boot basic security. Using Spring boot basic security , we can provide in memory authentication and authorization to our application.

  1. Spring boot basic security application – This will handle the authentication and authorization for our UI application.
  2. UI for Todo manager in angular – This is the Todo manager application which will leverage the basic spring boot security feature.

Part 1: Spring boot basic security application

In this part , we will be creating a simple spring boot application which provides basic security. Its basically a RESTful webservice which has endpoints to access and modify Todos information. To access the Todo information through API , user needs to authenticate himself. Below configuration enables basic security.

SecurityConfig.java

package com.myjavablog;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().
                authorizeRequests().antMatchers(HttpMethod.OPTIONS, "/**").permitAll().anyRequest().authenticated()
                .and().httpBasic();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("myjavablog").password("{noop}secure").roles("USER");
    }
}

Below is the Rest controller class (TodoController.java)-

package com.myjavablog.controller;

import com.myjavablog.model.Todo;
import com.myjavablog.model.User;
import com.myjavablog.repository.TodoRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;

@CrossOrigin(origins = "http://localhost:4200")
@RestController
@RequestMapping("/api")
public class TodoController {

    //@Autowired
    //private TodoRepository todoRepository;

    static List<Todo> list = new ArrayList<>();

    @GetMapping(produces = "application/json")
    @RequestMapping({ "/validateLogin" })
    public User validateLogin()
    {
        return new User("User successfully authenticated");
    }

    @GetMapping(produces = "application/json")
    @RequestMapping("/todos")
    public List<Todo> getTodos(){
        return list;
    }

    TodoController(){

        list.add(new Todo(1l,"Badminton", "Badminton at 6 am", "Pending"));
        list.add(new Todo(2l,"Cricket", "Cricket at 7 am", "Pending"));
        list.add(new Todo(3l,"Football", "Football at 8 am", "Pending"));
        list.add(new Todo(4l,"Cards", "Cards at 6 am", "Pending"));
        list.add(new Todo(5l,"TT", "TT at 6 am", "Completed"));
        list.add(new Todo(6l,"Golf", "Golf at 6 am", "Pending"));
        list.add(new Todo(7l,"Running", "Running at 6 am", "Pending"));
        list.add(new Todo(8l,"Walking", "Walking at 6 am", "Pending"));
        list.add(new Todo(9l,"Swimming", "Swimming at 6 am", "Completed"));
        list.add(new Todo(10l,"Reading", "Reading at 6 am", "Pending"));

        //return list;
    }

    @GetMapping("/todo/{id}")
    public Todo getTodo(@PathVariable Long id)
    {
        //return todoRepository.findById(id);

        for(Todo todo : list){

            if(todo.getId() == id){
                return todo;
            }
        }

        return null;
    }

    @DeleteMapping("/todo/{id}")
    public boolean deleteTodo(@PathVariable Long id){
        //todoRepository.deleteById(id);

        for(Todo todo : list){

            if(todo.getId() == id){
                list.remove(todo);
            }
        }

        return true;
    }

    @PostMapping("/todo")
    public Todo createTodo(@RequestBody Todo todo){

        list.add(todo);
        return todo;
        //return todoRepository.save(todo);
    }

    @PutMapping("/todo")
    public Todo updateTodo(@RequestBody Todo todo){


        for(Todo t : list){

            if(todo.getId() == t.getId()){
                list.remove(t);
                list.add(todo);
                return todo;
            }
        }

        return null;
        //return todoRepository.save(todo);
    }
}

Source code can be downloaded from below link –

Part 2: UI for Todo manager in angular 7

All the REST service calls are authenticated and authorized using the spring boot basic security. Before calling todo services , we need to pass authorization header with all requests from UI. All our requests to REST calls are intercepted encoded by base 64 encoding and then passed to REST API.

In basic security we pass on base 64 encoded string of username and password to server as authorization header in below format –

Authorization Header = “Basic” + Base64Encoder(username:password)

Step 1: Create new angular application

Refer below post for creating new angular application –

Angular Installation and Setup

Step 2: Create modules for material and primeng components

Create two modules for material(material.module.ts) and primeng( primeng.module.ts ) to define all the related components required in application. These two modules are also required to be imported in main module (app.module.ts)

Please refer below link for primeng and material configuration –

CRUD Operations using primeng datatable and Material Design

Step 3: Create components (Presentation layer)

Create components named header, footer, login,logout and todo components for Todo Manager application.

Todo manager application shows all todos in primeng datatable . Also we are allowed to perform CRUD operations on all todos. All CRUD operations are done in todo component as below –

Todo component –

  • components\todo\todo.component.html
  • components\todo\todo.component.ts

Step 4: Add the routing for application (Application Navigation/Routing)

We have to create a route for the application navigation. Below file contains routing configuration –

  • src\app\app-routing.module.ts
import { NgModule, ViewChildren } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { TodoComponent } from './components/todo/todo.component';
import { TodoAddComponent } from './components/todo-add/todo-add.component';
import { TodoEditComponent } from './components/todo-edit/todo-edit.component';
import { AuthGaurdService } from './services/auth-gaurd.service';
import { LogoutComponent } from './components/logout/logout.component';
import { LoginComponent } from './components/login/login.component';

const routes: Routes = [
  { path: 'todo-list', component: TodoComponent ,canActivate:[AuthGaurdService]},
  { path: 'todo-add', component: TodoAddComponent ,canActivate:[AuthGaurdService] },
  { path: 'todo-edit/:id', component: TodoEditComponent ,canActivate:[AuthGaurdService]},
  { path: '', component: TodoComponent,canActivate:[AuthGaurdService] },
  { path: 'login', component: LoginComponent },
  { path: 'logout', component: LogoutComponent,canActivate:[AuthGaurdService] }
];

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

All the routes are guarded by auth guard service. AuthGuardService checks ,if user is logged in to the application and then only it activates those routes configured in app-routing.module.ts .

AuthGuardService has canActivate() method which returns true if user is already logged into the application. If user is not logged into the application then it returns false and redirect him to login page.

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

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

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

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    if (this.authService.isUserLoggedIn())
      return true;

    this.router.navigate(['login']);
    return false;
  }
}

Step 5: Authentication and Todo service (Service Layer)

AuthenticationService (authentication.service.ts) – It handles user authentication into the application. It has authenticate( username, password ) method which receives username and password entered on login page and authenticate user using spring basic authentication method.

Whenever you hit webservice , SecurityConfig.java comes into picture. If you remember, we have configured basic security in spring boot application created earlier . When we hit todo service then all the time we are authenticated against spring boot basic security. We need to pass authorization header all the time while hitting webservice from UI.

Also it stores user information in session for checking user logged in status.

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { map } from 'rxjs/operators';

export class User {
  constructor(
    public status: string,
  ) { }
}

@Injectable({
  providedIn: 'root'
})
export class AuthenticationService {
  
  constructor(private httpClient: HttpClient){
  }

  authenticate(username, password) {
    const headers = new HttpHeaders({ Authorization: 'Basic ' + btoa(username + ':' + password) });
    return this.httpClient.get<User>('http://localhost:8081/api/validateLogin', { headers }).pipe(
      map(
        userData => {
          sessionStorage.setItem('username', username);
          return userData;
        }
      )

    );
  }

  isUserLoggedIn() {
    let user = sessionStorage.getItem('username')
    console.log(!(user === null))
    return !(user === null)
  }

  logOut() {
    sessionStorage.removeItem('username')
  }
}

We also have TodoService (todo.service.ts) to perform various operations on Todo information.

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable, of, throwError } from 'rxjs';
import { map, catchError, tap, retry } from 'rxjs/operators';
import { Todo } from './../domain/Todo';

@Injectable({
  providedIn: 'root'
})
export class TodoService {

  endpoint = 'http://localhost:8081/api';

  username = 'myjavablog';
  password = 'secure';

  constructor(private httpClient: HttpClient) {
  }

  // Http Options
  httpOptions = {
    headers: new HttpHeaders({
      'Content-Type': 'application/json'
    })
  }
  
  public deleteTodo(todoId) {

    const headers = new HttpHeaders({ Authorization: 'Basic ' + btoa(this.username + ':' + this.password) });
    return this.httpClient.delete<Todo>("http://localhost:8081/api/todo" + "/" + todoId, { headers });
  }

  public createTodo(todo) {

    const headers = new HttpHeaders({ Authorization: 'Basic ' + btoa(this.username + ':' + this.password) });
    return this.httpClient.post<Todo>("http://localhost:8081/api/todo", todo, { headers });
  }

  // To Get List Of Todos
  getTodoList(): Observable<any> {
    
    const headers = new HttpHeaders({ Authorization: 'Basic ' + btoa(this.username + ':' + this.password) });
    return this.httpClient.get<Todo[]>('http://localhost:8081/api/todos', { headers });
  }

  // HttpClient API get() method => Fetch Todo
  getTodo(id): Observable<Todo> {

    const headers = new HttpHeaders({ Authorization: 'Basic ' + btoa(this.username + ':' + this.password) });
    return this.httpClient.get<Todo>(this.endpoint + '/todos/' + id, { headers });
  }
  
  // HttpClient API put() method => Update Todo
  updateTodo(id, todo): Observable<Todo> {
    
    const headers = new HttpHeaders({ Authorization: 'Basic ' + btoa(this.username + ':' + this.password) });
    return this.httpClient.put<Todo>(this.endpoint + '/todo' , JSON.stringify(todo), { headers });
      
  }
}

You can download source code for this application from below link –

Step 6: Run the application

ng serve

Login page

Home page

Add todo –

Leave a Comment

Bitnami