Angular 9 + Spring Boot JWT (JSON Web Token) Authentication Example
In this tutorial, will see how to integrate and use Angular 9 with Spring Boot JWT. We will use implemented Spring Boot JWT Authentication Example from our previous tutorial. In addition to this will add new Controller class called EmployeeCrudController, contains all crud rest end point.
Note : The full source code for angular Spring boot jwt example can be downloaded at the end of this article.
- First we will create spring boot rest application, with Websecurity Config
- Create an Angular application with HttpInterceptor service
- Finally we will integrate api with Angular application
Lets start
Spring Boot JWT Project Structure
Controller
Let's create Employee Crud Controller, which will have all crud operations/rest end points to be invoked by Angular 9 UI.package com.techgeeknext.controller;
import com.techgeeknext.model.Employee;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
@CrossOrigin()
@RestController
@RequestMapping({ "/employees" })
public class EmployeeCrudController {
private List<Employee> employees = createList();
@GetMapping(produces = "application/json")
public List<Employee> firstPage() {
return employees;
}
@DeleteMapping(path = { "/{id}" })
public Employee delete(@PathVariable("id") int id) {
Employee deletedEmp = null;
for (Employee emp : employees) {
if (emp.getEmpId().equals(id)) {
employees.remove(emp);
deletedEmp = emp;
break;
}
}
return deletedEmp;
}
@PostMapping
public Employee create(@RequestBody Employee user) {
employees.add(user);
return user;
}
private static List<Employee> createList() {
List<Employee> tempEmployees = new ArrayList<>();
Employee emp1 = new Employee();
emp1.setName("emp1");
emp1.setDesignation("manager");
emp1.setEmpId("1");
emp1.setSalary(3000);
Employee emp2 = new Employee();
emp2.setName("emp2");
emp2.setDesignation("developer");
emp2.setEmpId("2");
emp2.setSalary(3000);
tempEmployees.add(emp1);
tempEmployees.add(emp2);
return tempEmployees;
}
}
Websecurity Config
Another change in this project is to add provision to allow OPTIONS call in the Websecurity Config -permitAll().antMatchers(HttpMethod.OPTIONS, "/**")
.
package com.techgeeknext.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
@Autowired
private UserDetailsService jwtUserDetailsService;
@Autowired
private JwtRequestFilter jwtRequestFilter;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// configure AuthenticationManager so that it knows from where to load
// user for matching credentials
// Use BCryptPasswordEncoder
auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
// We don't need CSRF for this example
httpSecurity.csrf().disable()
// dont authenticate this particular request
.authorizeRequests().antMatchers("/authenticate")
.permitAll().antMatchers(HttpMethod.OPTIONS, "/**")
.permitAll().
// all other requests need to be authenticated
anyRequest().authenticated().and().
// make sure we use stateless session; session won't be used to
// store user's state.
exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// Add a filter to validate the tokens with every request
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
}
Take a look at our suggested posts:
Testing
We can test Spring Boot JWT Example rest end points by using below steps:- Generate JSON Web Token (JWT) Create POST request (localhost:8080/authenticate) and provide username and password in request body as given below.
- Validate JSON Web Token (JWT) Now use GET request localhost:8080/greeting with above generated JWT Token in header request.
Angular Spring Boot JWT Flow:
Angular Changes
Now will develop Angular Project to implement JWT Authentication. Here is the structure of angular project.The new Angular 9 version is available now. The newest release again includes improvements in performance, the default is the Ivy renderer, smaller bundle size and many more. Check out Angular 9 features.
To know more about how to creat Angular 9 Spring Boot Example click here
Let's understand the important integration part in angular side
Authentication service
In authentication.service.ts, once the user's entered username and password have been successfully authenticated, we will save the JSON Web Token, which we will add to the JWT Authentication Authorization Header in the session.
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) {}
// Provide username and password for authentication, and once authentication is successful,
//store JWT token in session
authenticate(username, password) {
return this.httpClient
.post<any>("http://localhost:8080/authenticate", { username, password })
.pipe(
map(userData => {
sessionStorage.setItem("username", username);
let tokenStr = "Bearer " + userData.token;
sessionStorage.setItem("token", tokenStr);
return userData;
})
);
}
isUserLoggedIn() {
let user = sessionStorage.getItem("username");
console.log(!(user === null));
return !(user === null);
}
logOut() {
sessionStorage.removeItem("username");
}
}
HttpInterceptor service
Next we'll change the HttpInterceptor service called BasicAuthInterceptor Service (basic-auth-interceptor.service.ts). This service checks if the session has a legitimate username and string token, and then updates the headers of all outgoing HTTP requests. We're implementing the interceptor by extending the HttpInterceptor.
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler } from '@angular/common/http';
import { AuthenticationService } from './authentication.service';
@Injectable({
providedIn: 'root'
})
export class BasicAuthHtppInterceptorService implements HttpInterceptor {
constructor() { }
intercept(req: HttpRequest<any>, next: HttpHandler) {
if (sessionStorage.getItem('username') && sessionStorage.getItem('token')) {
req = req.clone({
setHeaders: {
Authorization: sessionStorage.getItem('token')
}
})
}
return next.handle(req);
}
}
We will now register the generated HTTPInterceptor using app.module.ts by updating it in the Provider section.
providers: [
{
provide:HTTP_INTERCEPTORS, useClass:BasicAuthHtppInterceptorService, multi:true
}
],
Running the Application End to End
Finally, we're ready to run our application as both spring boot and Angular application is running
Now if you go to localhost:4200, you can login using the credentials -username ='techgeeknext' ,password='password'. User will be authenticated using Basic Authentication and forwarded to employees page.see our integration output in browser
Download Source Code
The full source code for this article can be found on below.Download it here - Spring Boot JWT Authentication Example Code
Angular JWT Authentication Example Code