Implementing Login/Logout with JWT
Table of Contents
- Introduction
- Introduction to Spring Boot
- What is JWT?
- Project Setup
- Implementing Registration Feature
- Implementing Login Feature
- Authentication and Authorization using JWT
- Creating and Validating JWT Tokens
- Implementing Logout Feature
- Conclusion
Introduction
Recently, authentication and authorization have become very important issues in web applications. Especially when developing RESTful APIs, there are many considerations in handling user authentication because multiple clients need to be supported. Today, we will explore how to implement a login and logout system based on JWT (JSON Web Token) using Spring Boot.
Introduction to Spring Boot
Spring Boot is a project created to simplify application initialization and configuration in the Spring framework, which is a Java-based web application framework. Spring Boot automatically manages the necessary configurations and dependencies, allowing developers to focus on business logic.
Spring Boot offers several advantages:
- Allows for quick prototype development.
- Basic configurations are automatically handled.
- Includes an embedded Tomcat server, eliminating the need for separate server configuration.
What is JWT?
JWT (JSON Web Token) is a compact and independent standard for securely transmitting information using JSON format. JWT is widely used to handle user authentication and authorization in web applications. The features of JWT include:
- Self-contained reliability: The transmitted data is signed and can be verified.
- Simple structure for easy parsing.
- Can be transmitted via HTTP headers, providing good compatibility with various clients.
JWT consists of three components:
- Header: Contains token type and signing algorithm information.
- Payload: Contains user information and claims.
- Signature: Ensures the integrity of the data by signing based on the header and payload.
Project Setup
To create a Spring Boot project, we use Spring Initializr. Select the necessary dependencies such as Web, JPA, Spring Security, Lombok, and JWT library.
com.example
jwt-demo
0.0.1-SNAPSHOT
jar
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-data-jpa
org.springframework.boot
spring-boot-starter-security
io.jsonwebtoken
jjwt
0.9.1
org.projectlombok
lombok
1.18.12
provided
com.h2database
h2
runtime
After adding the above dependencies to the build.gradle file, set up the Spring Boot application. Write database connection and JPA settings in the application.properties
file.
Implementing Registration Feature
The registration feature essentially allows the user’s provided information to be stored in the database. A JPA entity class is created to save user information.
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.persistence.*;
@Entity
@Table(name = "users")
@Getter @Setter @NoArgsConstructor @AllArgsConstructor
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true, nullable = false)
private String username;
@Column(nullable = false)
private String password;
private String role;
}
Create a repository interface to handle the user information provided during registration.
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository {
User findByUsername(String username);
}
Create a service class to handle the registration requests.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private PasswordEncoder passwordEncoder;
public void registerUser(User user) {
user.setPassword(passwordEncoder.encode(user.getPassword()));
user.setRole("ROLE_USER");
userRepository.save(user);
}
}
Implementing Login Feature
The login feature is the process where a user provides authentication information to receive a JWT token from the server. To achieve this, we write a filter class that handles authentication.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private JwtTokenProvider jwtTokenProvider;
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {
String username = request.getParameter("username");
String password = request.getParameter("password");
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
return authenticationManager.authenticate(authRequest);
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
String token = jwtTokenProvider.createToken(authResult.getName());
response.addHeader("Authorization", "Bearer " + token);
response.getWriter().write("Login Successful");
}
}
Authentication and Authorization using JWT
This section implements the method to authenticate users when calling an API using JWT. We will create a filter that blocks requests if the JWT token is missing or invalid.
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class JwtAuthenticationFilter extends GenericFilterBean {
@Autowired
private JwtTokenProvider jwtTokenProvider;
@Override
public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
String token = request.getHeader("Authorization");
if (token != null && jwtTokenProvider.validateToken(token)) {
Authentication authentication = jwtTokenProvider.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
chain.doFilter(request, response);
}
}
Creating and Validating JWT Tokens
Create a utility class for generating and validating JWT tokens. This class will include various methods for handling JWT.
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.JwtParser;
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 JwtTokenProvider {
private final String SECRET_KEY = "mySecretKey";
public String createToken(String username) {
Map claims = new HashMap<>();
return Jwts.builder()
.setClaims(claims)
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) // 10 hours
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
public boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token);
return true;
} catch (Exception e) {
return false;
}
}
public Authentication getAuthentication(String token) {
// Implement user authentication logic
}
}
Implementing Logout Feature
The logout feature allows the user to terminate authentication, which is usually implemented by deleting the JWT token from the client. Furthermore, if the server needs to invalidate the token, a blacklist must be managed.
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/auth")
public class AuthController {
@PostMapping("/logout")
public ResponseEntity> logout(HttpServletRequest request) {
String token = request.getHeader("Authorization");
// Logic for registering the token in the blacklist
return ResponseEntity.ok("Logout Successful");
}
}
Conclusion
In this tutorial, we explored how to implement login/logout features based on JWT using Spring Boot. JWT is a useful tool for handling authentication and authorization in web services, and it will be a great help in future application development. Additionally, researching more about security and session management can help ensure better security.
If you want to expand your knowledge related to authentication and authorization with JWT, it is recommended to study security best practices along with protocols like OAuth2 and OpenID Connect.