Show List
Spring Boot Security Using JWT
In this example we will create Spring Boot REST web services and add security controls. Only authenticated and authorized users will be able to access the service. We will be using in memory H2 database to store users list to authenticate users against it.
JWT (JSON Web Token) authentication is a token-based stateless authentication mechanism. User first authenticates using credentials. On successful authentication, server sends JWT in the response. The user sends JWT in the subsequent requests.
- Student: To manage students list through student web service
- Teacher: To manage teachers list through teacher web service
- AppUser: To store user credentials and roles/authorities.
We will have security rules so that only users with ADMIN role will be able to access teachers service and users with ADMIN or USER role would be able to access students service.
1. Go to Spring initializr website and create a Java Maven Project with dependencies: JPA, H2 database, Web and Spring Security. Download the project zip and extract to a folder.
2. Import the project into IDE (I am using IntelliJ Idea). Pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2. Create following classes in the com.example.demo.model package:
- Student : Used to interact with database table student using Spring Data JDBC
- Teacher : Used to interact with database table teacher using Spring Data JDBC
- AppUser : To create the table to store user credentials and authorities
- AuthenticationRequest: Model of request sent for authentication
- Authentication Response: Returns JWT when the authentication is successful
package com.example.demo.model;
import javax.persistence.*;
@Entity
@Table
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int student_id;
private String name;
private String grade;
public Student(){
}
public Student( String name, String grade) {
this.name = name;
this.grade = grade;
}
public int getStudent_id() {
return student_id;
}
public void setStudent_id(int student_id) {
this.student_id = student_id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGrade() {
return grade;
}
public void setGrade(String grade) {
this.grade = grade;
}
}
package com.example.demo.model;
import javax.persistence.*;
@Entity
@Table
public class Teacher {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int teacher_id;
private String name;
private String subject;
public Teacher(){
}
public Teacher(String name, String grade) {
this.name = name;
this.subject = grade;
}
public int getTeacher_id() {
return teacher_id;
}
public void setTeacher_id(int student_id) {
this.teacher_id = student_id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGrade() {
return subject;
}
public void setGrade(String grade) {
this.subject = grade;
}
}
package com.example.demo.model;
import javax.persistence.*;
@Entity
@Table
public class AppUser {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int user_id;
private String name;
private String username;
private String password;
private String role;
public AppUser(){
}
public AppUser(String name, String username, String password, String role) {
this.name = name;
this.username = username;
this.password = password;
this.role = role;
}
public int getUser_id() {
return user_id;
}
public void setUser_id(int user_id) {
this.user_id = user_id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
}
package com.example.demo.model;
import java.io.Serializable;
public class AuthenticationRequest implements Serializable {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
//need default constructor for JSON Parsing
public AuthenticationRequest() {
}
public AuthenticationRequest(String username, String password) {
this.setUsername(username);
this.setPassword(password);
}
}
package com.example.demo.model;
import java.io.Serializable;
public class AuthenticationResponse implements Serializable {
private final String jwt;
public AuthenticationResponse(String jwt) {
this.jwt = jwt;
}
public String getJwt() {
return jwt;
}
}
3. Create repo classes StudentRepo, TeacherRepo and UserRepo extending CrudRepository. CrudRepository will provide the Create, Read, Update and Delete methods.
package com.example.demo.dao;
import com.example.demo.model.Student;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface StudentRepo extends CrudRepository<Student, Long> {}
package com.example.demo.dao;
import com.example.demo.model.Student;
import com.example.demo.model.Teacher;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface TeacherRepo extends CrudRepository<Teacher, Long> {}
package com.example.demo.dao;
import com.example.demo.model.AppUser;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepo extends CrudRepository<AppUser, Long> {
AppUser findByUsername(String username);
}
AppUserDetailsService:
package com.example.demo.service;
import com.example.demo.dao.UserRepo;
import com.example.demo.model.AppUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.List;
@Service
public class AppUserDetailsService implements UserDetailsService {
@Autowired
UserRepo repoUsr;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
AppUser user = repoUsr.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException(username);
}
UserDetails usr = User.withUsername(user.getUsername()).password(user.getPassword()).authorities(user.getRole()).build();
return usr;
}
}
4. Create controller class StudentController, TeacherController and UserController.
StudentController also has method to handle authentication requests sent to /authenticate end point.
StudentController class:
package com.example.demo.controller;
import com.example.demo.dao.StudentRepo;
import com.example.demo.model.AuthenticationRequest;
import com.example.demo.model.AuthenticationResponse;
import com.example.demo.model.Student;
import com.example.demo.service.AppUserDetailsService;
import com.example.demo.util.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
@RestController
public class StudentController {
@Autowired
private StudentRepo repo;
@Autowired
private AppUserDetailsService userDetailsService;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Autowired
private AuthenticationManager authenticationManager;
@GetMapping("/students")
private List<Student> getAllStudents(){
return (List<Student>) repo.findAll();
}
@GetMapping("/student/{id}")
private Optional<Student> getStudents(@PathVariable Long id){
return repo.findById(id);
}
@PostMapping("/students")
private Student addStudent(@RequestBody Student newStudent){
return repo.save(newStudent);
}
@DeleteMapping("/students/{id}")
private void removeStudent(@PathVariable Long id){
repo.deleteById(id);
}
@PutMapping("/students/{id}")
private Student updateStudent(@RequestBody Student newStudent, @PathVariable Long id){
return repo.findById(id)
.map(student -> {
student.setName(newStudent.getName());
student.setGrade(newStudent.getGrade());
return repo.save(student);
})
.orElseGet(() -> {
newStudent.setStudent_id(Math.toIntExact(id));
return repo.save(newStudent);
});
}
@RequestMapping(value = "/authenticate", method = RequestMethod.POST)
public ResponseEntity<?> createAuthenticationToken(@RequestBody AuthenticationRequest authenticationRequest) throws Exception {
System.out.println("createAuthenticationToken called with " + authenticationRequest.getUsername()
+ " " + authenticationRequest.getPassword());
try {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(authenticationRequest.getUsername(), authenticationRequest.getPassword())
);
System.out.println("Authenticated successfully");
}
catch (BadCredentialsException e) {
throw new Exception("Incorrect username or password", e);
}
final UserDetails userDetails = userDetailsService
.loadUserByUsername(authenticationRequest.getUsername());
final String jwt = jwtTokenUtil.generateToken(userDetails);
return ResponseEntity.ok(new AuthenticationResponse(jwt));
}
}
TeacherController class:
package com.example.demo.controller;
import com.example.demo.dao.TeacherRepo;
import com.example.demo.model.Teacher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
@RestController
public class TeacherController {
@Autowired
private TeacherRepo repo;
@GetMapping("/teachers")
private List<Teacher> getAllTeachers(){
return (List<Teacher>) repo.findAll();
}
@GetMapping("/teacher/{id}")
private Optional<Teacher> getTeachers(@PathVariable Long id){
return repo.findById(id);
}
@PostMapping("/teachers")
private Teacher addTeacher(@RequestBody Teacher newTeacher){
return repo.save(newTeacher);
}
@DeleteMapping("/teachers/{id}")
private void removeTeacher(@PathVariable Long id){
repo.deleteById(id);
}
@PutMapping("/teachers/{id}")
private Teacher updateTeacher(@RequestBody Teacher newTeacher, @PathVariable Long id){
return repo.findById(id)
.map(teacher -> {
teacher.setName(newTeacher.getName());
teacher.setGrade(newTeacher.getGrade());
return repo.save(teacher);
})
.orElseGet(() -> {
newTeacher.setTeacher_id(Math.toIntExact(id));
return repo.save(newTeacher);
});
}
}
UserController:
package com.example.demo.controller;
import com.example.demo.dao.UserRepo;
import com.example.demo.model.AppUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
@RestController
public class UserController {
@Autowired
private UserRepo repo;
@GetMapping("/users")
private List<AppUser> getAllUsers(){
return (List<AppUser>) repo.findAll();
}
@GetMapping("/user/{id}")
private Optional<AppUser> getUsers(@PathVariable Long id){
return repo.findById(id);
}
@PostMapping("/users")
private AppUser addUser(@RequestBody AppUser newAppUser){
return repo.save(newAppUser);
}
@DeleteMapping("/users/{id}")
private void removeUser(@PathVariable Long id){
repo.deleteById(id);
}
@PutMapping("/users/{id}")
private AppUser updateUser(@RequestBody AppUser newAppUser, @PathVariable Long id){
return repo.findById(id)
.map(user -> {
user.setName(newAppUser.getName());
user.setRole(newAppUser.getRole());
return repo.save(user);
})
.orElseGet(() -> {
newAppUser.setUser_id(Math.toIntExact(id));
return repo.save(newAppUser);
});
}
}
5. Create SecurityConfig class in the config package. This class extends WebSecurityConfigurerAdapter and overrides the configure methods. UserDetailService (custom class AppUserDetailsService) is used as authentication manager. AppUserDetailsService class loads the user information from database and returns UserDetails object.
A custom filter JwtTokenFilter is called before UsernamePasswordAuthenticationFilter. This filter checks whether user has sent a valid JWT token in the header. If valid token is present then the request is marked authenticated.
antmatchers are used to make /authenticate end point public. /students can be used only by authenticated users with authority "ADMIN" or "USER". /teachers can be used only by authenticated users with authority "ADMIN".
SecurityConfig class:
package com.example.demo.config;
import com.example.demo.dao.UserRepo;
import com.example.demo.service.AppUserDetailsService;
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.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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.servlet.http.HttpServletResponse;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtTokenFilter jwtTokenFilter;
@Autowired
private AppUserDetailsService appUserDetailsService;
@Autowired
UserRepo repoUsr;
@Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(appUserDetailsService);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// Enable CORS and disable CSRF
http = http.cors().and().csrf().disable();
// Set session management to stateless
http = http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and();
// Set unauthorized requests exception handler
http = http
.exceptionHandling()
.authenticationEntryPoint(
(request, response, ex) -> {
response.sendError(
HttpServletResponse.SC_UNAUTHORIZED,
ex.getMessage()
);
}
)
.and();
// Set permissions on endpoints
http.authorizeRequests()
// Our public endpoints
.antMatchers(HttpMethod.POST, "/authenticate").permitAll()
// Our private endpoints
.antMatchers(HttpMethod.GET, "/students").hasAnyAuthority("ADMIN", "USER")
.antMatchers(HttpMethod.GET, "/teachers").hasAuthority("ADMIN")
.anyRequest().authenticated();
// Add JWT token filter
http.addFilterBefore(
jwtTokenFilter,
UsernamePasswordAuthenticationFilter.class
);
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
JWTTokenFilter class:
package com.example.demo.config;
import com.example.demo.dao.UserRepo;
import com.example.demo.service.AppUserDetailsService;
import com.example.demo.util.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
@Component
public class JwtTokenFilter extends OncePerRequestFilter {
@Autowired
private AppUserDetailsService appUserDetailsService;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Autowired
private UserRepo userRepo;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain)
throws ServletException, IOException {
// Get authorization header and validate
final String header = request.getHeader(HttpHeaders.AUTHORIZATION);
String username = null;
String jwt = null;
if (header!= null && header.startsWith("Bearer ")) {
System.out.println("Header contains bearer token");
jwt = header.substring(7);
username = jwtTokenUtil.extractUsername(jwt);
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = appUserDetailsService.loadUserByUsername(username);
if (jwtTokenUtil.validateToken(jwt, userDetails)) {
System.out.println("JWT Token is Valid.");
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
chain.doFilter(request, response);
}
}
JwtTokenUtil class:
package com.example.demo.util;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
@Service
public class JwtTokenUtil {
private String SECRET_KEY = "secret";
public String extractUsername(String token) {
return extractClaim(token, Claims::getSubject);
}
public Date extractExpiration(String token) {
return extractClaim(token, Claims::getExpiration);
}
public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
}
private Claims extractAllClaims(String token) {
return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
}
private Boolean isTokenExpired(String token) {
return extractExpiration(token).before(new Date());
}
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return createToken(claims, userDetails.getUsername());
}
private String createToken(Map<String, Object> claims, String subject) {
return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10))
.signWith(SignatureAlgorithm.HS256, SECRET_KEY).compact();
}
public Boolean validateToken(String token, UserDetails userDetails) {
final String username = extractUsername(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
}
6. Add below line in the application.properties file. This will make JPA queries appear in the log
spring.jpa.show-sql=true
7. In the mail class use ApplicationRunner to load the initial data to database tables student, teacher and appuser
package com.example.demo;
import com.example.demo.dao.StudentRepo;
import com.example.demo.dao.TeacherRepo;
import com.example.demo.dao.UserRepo;
import com.example.demo.model.Student;
import com.example.demo.model.Teacher;
import com.example.demo.model.AppUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@SpringBootApplication
public class DemoApplication implements ApplicationRunner {
@Autowired
StudentRepo repoSt;
@Autowired
TeacherRepo repoTch;
@Autowired
UserRepo repoUsr;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Override
public void run(ApplicationArguments args) throws Exception {
repoSt.save(new Student("Ana", "One"));
repoSt.save(new Student("Bob", "Two"));
repoSt.save(new Student("Charlie", "One"));
repoSt.save(new Student("David", "Three"));
repoTch.save(new Teacher("Edward", "English"));
repoTch.save(new Teacher("Mary", "Math"));
repoTch.save(new Teacher("Sana", "Science"));
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
repoUsr.save(new AppUser("user1","username1",encoder.encode("password1"),"USER"));
repoUsr.save(new AppUser("user2","username2",encoder.encode("password2"),"ADMIN"));
repoUsr.save(new AppUser("user","user",encoder.encode("password"),"USER"));
}
}
8. Run the Spring Boot application and test using web service client (such as Postman).
"C:\Program Files\Java\jdk-11.0.15\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2021.2\lib\idea_rt.jar=54488:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2021.2\bin" -Dfile.encoding=UTF-8 -classpath C:\Users\mail2\Downloads\spring-security-using-jwt\target\classes;D:\.m2\repository\org\springframework\boot\spring-boot-starter-data-jpa\2.7.3\spring-boot-starter-data-jpa-2.7.3.jar;D:\.m2\repository\org\springframework\boot\spring-boot-starter-aop\2.7.3\spring-boot-starter-aop-2.7.3.jar;D:\.m2\repository\org\aspectj\aspectjweaver\1.9.7\aspectjweaver-1.9.7.jar;D:\.m2\repository\org\springframework\boot\spring-boot-starter-jdbc\2.7.3\spring-boot-starter-jdbc-2.7.3.jar;D:\.m2\repository\com\zaxxer\HikariCP\4.0.3\HikariCP-4.0.3.jar;D:\.m2\repository\org\springframework\spring-jdbc\5.3.22\spring-jdbc-5.3.22.jar;D:\.m2\repository\jakarta\transaction\jakarta.transaction-api\1.3.3\jakarta.transaction-api-1.3.3.jar;D:\.m2\repository\jakarta\persistence\jakarta.persistence-api\2.2.3\jakarta.persistence-api-2.2.3.jar;D:\.m2\repository\org\hibernate\hibernate-core\5.6.10.Final\hibernate-core-5.6.10.Final.jar;D:\.m2\repository\org\jboss\logging\jboss-logging\3.4.3.Final\jboss-logging-3.4.3.Final.jar;D:\.m2\repository\net\bytebuddy\byte-buddy\1.12.13\byte-buddy-1.12.13.jar;D:\.m2\repository\antlr\antlr\2.7.7\antlr-2.7.7.jar;D:\.m2\repository\org\jboss\jandex\2.4.2.Final\jandex-2.4.2.Final.jar;D:\.m2\repository\com\fasterxml\classmate\1.5.1\classmate-1.5.1.jar;D:\.m2\repository\org\hibernate\common\hibernate-commons-annotations\5.1.2.Final\hibernate-commons-annotations-5.1.2.Final.jar;D:\.m2\repository\org\glassfish\jaxb\jaxb-runtime\2.3.6\jaxb-runtime-2.3.6.jar;D:\.m2\repository\org\glassfish\jaxb\txw2\2.3.6\txw2-2.3.6.jar;D:\.m2\repository\com\sun\istack\istack-commons-runtime\3.0.12\istack-commons-runtime-3.0.12.jar;D:\.m2\repository\com\sun\activation\jakarta.activation\1.2.2\jakarta.activation-1.2.2.jar;D:\.m2\repository\org\springframework\data\spring-data-jpa\2.7.2\spring-data-jpa-2.7.2.jar;D:\.m2\repository\org\springframework\data\spring-data-commons\2.7.2\spring-data-commons-2.7.2.jar;D:\.m2\repository\org\springframework\spring-orm\5.3.22\spring-orm-5.3.22.jar;D:\.m2\repository\org\springframework\spring-context\5.3.22\spring-context-5.3.22.jar;D:\.m2\repository\org\springframework\spring-tx\5.3.22\spring-tx-5.3.22.jar;D:\.m2\repository\org\springframework\spring-beans\5.3.22\spring-beans-5.3.22.jar;D:\.m2\repository\org\slf4j\slf4j-api\1.7.36\slf4j-api-1.7.36.jar;D:\.m2\repository\org\springframework\spring-aspects\5.3.22\spring-aspects-5.3.22.jar;D:\.m2\repository\org\springframework\boot\spring-boot-starter-security\2.7.3\spring-boot-starter-security-2.7.3.jar;D:\.m2\repository\org\springframework\boot\spring-boot-starter\2.7.3\spring-boot-starter-2.7.3.jar;D:\.m2\repository\org\springframework\boot\spring-boot\2.7.3\spring-boot-2.7.3.jar;D:\.m2\repository\org\springframework\boot\spring-boot-autoconfigure\2.7.3\spring-boot-autoconfigure-2.7.3.jar;D:\.m2\repository\org\springframework\boot\spring-boot-starter-logging\2.7.3\spring-boot-starter-logging-2.7.3.jar;D:\.m2\repository\ch\qos\logback\logback-classic\1.2.11\logback-classic-1.2.11.jar;D:\.m2\repository\ch\qos\logback\logback-core\1.2.11\logback-core-1.2.11.jar;D:\.m2\repository\org\apache\logging\log4j\log4j-to-slf4j\2.17.2\log4j-to-slf4j-2.17.2.jar;D:\.m2\repository\org\apache\logging\log4j\log4j-api\2.17.2\log4j-api-2.17.2.jar;D:\.m2\repository\org\slf4j\jul-to-slf4j\1.7.36\jul-to-slf4j-1.7.36.jar;D:\.m2\repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\.m2\repository\org\yaml\snakeyaml\1.30\snakeyaml-1.30.jar;D:\.m2\repository\org\springframework\spring-aop\5.3.22\spring-aop-5.3.22.jar;D:\.m2\repository\org\springframework\security\spring-security-config\5.7.3\spring-security-config-5.7.3.jar;D:\.m2\repository\org\springframework\security\spring-security-web\5.7.3\spring-security-web-5.7.3.jar;D:\.m2\repository\org\springframework\spring-expression\5.3.22\spring-expression-5.3.22.jar;D:\.m2\repository\org\springframework\boot\spring-boot-starter-web\2.7.3\spring-boot-starter-web-2.7.3.jar;D:\.m2\repository\org\springframework\boot\spring-boot-starter-json\2.7.3\spring-boot-starter-json-2.7.3.jar;D:\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.13.3\jackson-datatype-jdk8-2.13.3.jar;D:\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.13.3\jackson-datatype-jsr310-2.13.3.jar;D:\.m2\repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.13.3\jackson-module-parameter-names-2.13.3.jar;D:\.m2\repository\org\springframework\boot\spring-boot-starter-tomcat\2.7.3\spring-boot-starter-tomcat-2.7.3.jar;D:\.m2\repository\org\apache\tomcat\embed\tomcat-embed-core\9.0.65\tomcat-embed-core-9.0.65.jar;D:\.m2\repository\org\apache\tomcat\embed\tomcat-embed-el\9.0.65\tomcat-embed-el-9.0.65.jar;D:\.m2\repository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.65\tomcat-embed-websocket-9.0.65.jar;D:\.m2\repository\org\springframework\spring-web\5.3.22\spring-web-5.3.22.jar;D:\.m2\repository\org\springframework\spring-webmvc\5.3.22\spring-webmvc-5.3.22.jar;D:\.m2\repository\com\h2database\h2\2.1.214\h2-2.1.214.jar;D:\.m2\repository\io\jsonwebtoken\jjwt\0.9.1\jjwt-0.9.1.jar;D:\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.13.3\jackson-databind-2.13.3.jar;D:\.m2\repository\com\fasterxml\jackson\core\jackson-annotations\2.13.3\jackson-annotations-2.13.3.jar;D:\.m2\repository\com\fasterxml\jackson\core\jackson-core\2.13.3\jackson-core-2.13.3.jar;D:\.m2\repository\javax\xml\bind\jaxb-api\2.3.0\jaxb-api-2.3.0.jar;D:\.m2\repository\jakarta\xml\bind\jakarta.xml.bind-api\2.3.3\jakarta.xml.bind-api-2.3.3.jar;D:\.m2\repository\jakarta\activation\jakarta.activation-api\1.2.2\jakarta.activation-api-1.2.2.jar;D:\.m2\repository\org\springframework\spring-core\5.3.22\spring-core-5.3.22.jar;D:\.m2\repository\org\springframework\spring-jcl\5.3.22\spring-jcl-5.3.22.jar;D:\.m2\repository\org\springframework\security\spring-security-core\5.7.3\spring-security-core-5.7.3.jar;D:\.m2\repository\org\springframework\security\spring-security-crypto\5.7.3\spring-security-crypto-5.7.3.jar com.example.demo.DemoApplication . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.7.3) 2022-09-14 09:12:02.816 INFO 14400 --- [ main] com.example.demo.DemoApplication : Starting DemoApplication using Java 11.0.15 on sm15 with PID 14400 (C:\Users\mail2\Downloads\spring-security-using-jwt\target\classes started by mail2 in C:\Users\mail2\Downloads\spring-security-using-jwt) 2022-09-14 09:12:02.816 INFO 14400 --- [ main] com.example.demo.DemoApplication : No active profile set, falling back to 1 default profile: "default" 2022-09-14 09:12:03.800 INFO 14400 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode. 2022-09-14 09:12:03.879 INFO 14400 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 69 ms. Found 3 JPA repository interfaces. 2022-09-14 09:12:04.832 INFO 14400 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2022-09-14 09:12:04.847 INFO 14400 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2022-09-14 09:12:04.847 INFO 14400 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.65] 2022-09-14 09:12:04.988 INFO 14400 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2022-09-14 09:12:04.988 INFO 14400 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2109 ms 2022-09-14 09:12:05.207 INFO 14400 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... 2022-09-14 09:12:05.550 INFO 14400 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. 2022-09-14 09:12:05.628 INFO 14400 --- [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default] 2022-09-14 09:12:05.722 INFO 14400 --- [ main] org.hibernate.Version : HHH000412: Hibernate ORM core version 5.6.10.Final 2022-09-14 09:12:05.972 INFO 14400 --- [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.1.2.Final} 2022-09-14 09:12:06.144 INFO 14400 --- [ main] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect Hibernate: drop table if exists app_user CASCADE Hibernate: drop table if exists student CASCADE Hibernate: drop table if exists teacher CASCADE Hibernate: create table app_user (user_id integer generated by default as identity, name varchar(255), password varchar(255), role varchar(255), username varchar(255), primary key (user_id)) Hibernate: create table student (student_id integer generated by default as identity, grade varchar(255), name varchar(255), primary key (student_id)) Hibernate: create table teacher (teacher_id integer generated by default as identity, name varchar(255), subject varchar(255), primary key (teacher_id)) 2022-09-14 09:12:07.151 INFO 14400 --- [ main] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform] 2022-09-14 09:12:07.159 INFO 14400 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default' 2022-09-14 09:12:07.694 WARN 14400 --- [ main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning 2022-09-14 09:12:08.136 INFO 14400 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Will secure any request with [org.springframework.security.web.session.DisableEncodeUrlFilter@368ff8be, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@41bbdd8a, org.springframework.security.web.context.SecurityContextPersistenceFilter@7c9512c6, org.springframework.security.web.header.HeaderWriterFilter@1f1ffc18, org.springframework.web.filter.CorsFilter@3bf4644c, org.springframework.security.web.authentication.logout.LogoutFilter@1bba9862, com.example.demo.config.JwtTokenFilter@62c6db99, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@1b79df53, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@1322b542, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@30adae45, org.springframework.security.web.session.SessionManagementFilter@61ca5134, org.springframework.security.web.access.ExceptionTranslationFilter@6244afc4, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@39a9becc] 2022-09-14 09:12:08.418 INFO 14400 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2022-09-14 09:12:08.432 INFO 14400 --- [ main] com.example.demo.DemoApplication : Started DemoApplication in 6.195 seconds (JVM running for 6.729) Hibernate: insert into student (student_id, grade, name) values (default, ?, ?) Hibernate: insert into student (student_id, grade, name) values (default, ?, ?) Hibernate: insert into student (student_id, grade, name) values (default, ?, ?) Hibernate: insert into student (student_id, grade, name) values (default, ?, ?) Hibernate: insert into teacher (teacher_id, name, subject) values (default, ?, ?) Hibernate: insert into teacher (teacher_id, name, subject) values (default, ?, ?) Hibernate: insert into teacher (teacher_id, name, subject) values (default, ?, ?) Hibernate: insert into app_user (user_id, name, password, role, username) values (default, ?, ?, ?, ?) Hibernate: insert into app_user (user_id, name, password, role, username) values (default, ?, ?, ?, ?) Hibernate: insert into app_user (user_id, name, password, role, username) values (default, ?, ?, ?, ?)
First, send post request to /authenticate end point sending credentials to get the jwt token.
In the subsequent request, send JWT token in the header with key Authorization
Source Code:
https://github.com/it-code-lab/spring-security-using-jwt
Leave a Comment