Hello! In this blog post, we will explain how to develop a backend service using Spring Boot and implement login and logout functions using JSON Web Token (JWT). JWT is a widely used method for transmitting and validating authentication information in web applications. Through this tutorial, we will explore the concept of JWT in detail and its implementation.
Table of Contents
- 1. JWT Concept
- 2. Spring Boot Project Setup
- 3. Entity Configuration
- 4. JWT Creation and Validation
- 5. Login Function Implementation
- 6. Logout Function Implementation
- 7. Comprehensive Test
- 8. Conclusion
1. JWT Concept
JWT (JSON Web Token) is a representative method for securely transmitting authentication information between two parties. JWT consists of three parts:
- Header: Contains the type of token (JWT) and algorithm information.
- Payload: Includes user information and other claims.
- Signature: A signature created based on the Header and Payload, ensuring integrity.
The main advantage of JWT is that it allows information to be maintained on the client side, eliminating the need for the server to manage state. This is particularly useful in distributed systems or microservices architectures.
2. Spring Boot Project Setup
Let’s start by creating a simple RESTful API using Spring Boot. We will manage libraries using Maven.
pom.xml
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>jwt-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>jwt-demo</name>
<description>JWT Demo Project</description>
<properties>
<java.version>17</java.version>
<spring-boot.version>2.6.6</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
After setting up the necessary dependencies as shown above, create the project directory and write the application class.
src/main/java/com/example/jwtdemo/JwtDemoApplication.java
package com.example.jwtdemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class JwtDemoApplication {
public static void main(String[] args) {
SpringApplication.run(JwtDemoApplication.class, args);
}
}
3. Entity Configuration
To manage users, we will configure a User entity. This entity is needed to store user information.
src/main/java/com/example/jwtdemo/model/User.java
package com.example.jwtdemo.model;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
// Getters and setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
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;
}
}
4. JWT Creation and Validation
Now, let’s write a utility class to create and validate JWTs. This class will include methods to create and validate JWT tokens.
src/main/java/com/example/jwtdemo/util/JwtUtil.java
package com.example.jwtdemo.util;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@Component
public class JwtUtil {
private final String SECRET_KEY = "secret"; // Secret key
private final int EXPIRATION_TIME = 1000 * 60 * 60; // 1 hour
// Generate JWT
public String generateToken(String username) {
Map claims = new HashMap<>();
return createToken(claims, username);
}
private String createToken(Map claims, String subject) {
return Jwts.builder()
.setClaims(claims)
.setSubject(subject)
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
// Validate JWT
public boolean validateToken(String token, String username) {
final String extractedUsername = extractUsername(token);
return (extractedUsername.equals(username) && !isTokenExpired(token));
}
private boolean isTokenExpired(String token) {
return extractExpiration(token).before(new Date());
}
private Date extractExpiration(String token) {
return extractAllClaims(token).getExpiration();
}
private Claims extractAllClaims(String token) {
return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
}
public String extractUsername(String token) {
return extractAllClaims(token).getSubject();
}
}
5. Login Function Implementation
Now we will implement the login function. If the user provides valid credentials, we will generate and return a JWT.
src/main/java/com/example/jwtdemo/controller/AuthController.java
package com.example.jwtdemo.controller;
import com.example.jwtdemo.model.User;
import com.example.jwtdemo.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/auth")
public class AuthController {
@Autowired
private JwtUtil jwtUtil;
@PostMapping("/login")
public Map login(@RequestBody User user) {
// This part requires logic to check user information in the database.
if ("test".equals(user.getUsername()) && "password".equals(user.getPassword())) {
String token = jwtUtil.generateToken(user.getUsername());
Map response = new HashMap<>();
response.put("token", token);
return response;
} else {
throw new RuntimeException("Invalid credentials");
}
}
}
6. Logout Function Implementation
Logout is typically performed by deleting or invalidating the JWT on the client side. Generally, logout is handled on the client side.
Here is an example of how to remove the JWT on the client:
localStorage.removeItem('token');
Since the server does not manage user state, there is no need for a separate logout endpoint on the server.
7. Comprehensive Test
Now that all implementations are complete, you can test the API using Postman or CURL.
- Login Request:
POST http://localhost:8080/auth/login
– Send user information in JSON format in the Body.
{
"username": "test",
"password": "password"
}
response
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
You can use the received JWT to make other API calls by adding it to the Authorization header as Bearer.
8. Conclusion
In this tutorial, we learned how to implement login and logout functions using JWT with Spring Boot. JWT is a lightweight authentication mechanism that can be effectively applied in various situations. Using JWT in practice can enhance security through efficient authentication and authorization management. We recommend experiencing various features based on JWT in the future.
Thank you! Questions and feedback are welcome in the comments below.