1. Introduction
Recently, the importance of backend development has been highlighted due to the advancement of microservices architecture and RESTful APIs. In today’s lecture, we will learn how to implement user authentication using JSON Web Token (JWT) through backend development with Spring Boot. This lecture focuses on adding a JWT-based token provider that includes login and logout features.
2. What is Spring Boot?
Spring Boot is a tool that helps developers create Spring applications quickly and easily based on the Spring framework. It allows for the easy development of demo and real applications without complex XML configurations. Additionally, Spring Boot supports embedded servers, enabling applications to be run locally without deployment to an external server.
3. Understanding JWT
JSON Web Token (JWT) is an open standard for transmitting data, used to securely send information between client and server. JWT is mainly used for authentication and information exchange. A JWT consists of three parts:
- Header: Defines the type of token and the encryption algorithm.
- Payload: This part stores user information, such as user ID.
- Signature: The part that is signed with a secret key by combining the header and payload.
4. Setting up a Spring Boot Project
First, you need to set up a Spring Boot project. Visit the Spring Initializr website to create a new project. You should add the following dependencies:
- Spring Web
- Spring Security
- Spring Data JPA
- H2 Database (or your desired database)
- jjwt (library for using JWT)
5. Creating the User Entity Class
Create an entity class to store user information. Here is an example of the User entity class:
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true)
private String username;
private String password;
// Getter and Setter methods
}
6. Writing the JWT Utility Class
Write a utility class to create and validate JWT.
@Component
public class JwtUtil {
private String secretKey = "mySecretKey"; // Secret key
public String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + 10 * 60 * 1000)) // Set expiration time
.signWith(SignatureAlgorithm.HS256, secretKey)
.compact();
}
public boolean validateToken(String token, String username) {
final String extractedUsername = extractUsername(token);
return (extractedUsername.equals(username) && !isTokenExpired(token));
}
public String extractUsername(String token) {
return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody().getSubject();
}
private boolean isTokenExpired(String token) {
return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody().getExpiration().before(new Date());
}
}
7. Setting Up Spring Security
Set up Spring Security to implement a JWT-based authentication process. First, configure the SecurityFilterChain.
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtRequestFilter jwtRequestFilter;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests().antMatchers("/authenticate").permitAll()
.anyRequest().authenticated();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("user").password(passwordEncoder().encode("password")).roles("USER");
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
8. Writing the JWT Request Filter
Create a JWT Request Filter that filters the JWT from user requests to verify authentication.
@Component
public class JwtRequestFilter extends OncePerRequestFilter {
@Autowired
private JwtUtil jwtUtil;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
final String authorizationHeader = request.getHeader("Authorization");
String username = null;
String jwt = null;
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
jwt = authorizationHeader.substring(7);
username = jwtUtil.extractUsername(jwt);
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
// Process authentication for the specified user
}
chain.doFilter(request, response);
}
}
9. Writing the Login and Token Generation Controller
Create a controller that handles user login requests and generates JWT.
@RestController
public class AuthController {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private JwtUtil jwtUtil;
@PostMapping("/authenticate")
public ResponseEntity> authenticate(@RequestBody AuthRequest authRequest) throws Exception {
try {
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(authRequest.getUsername(), authRequest.getPassword()));
} catch (BadCredentialsException e) {
throw new Exception("Invalid username or password", e);
}
final String jwt = jwtUtil.generateToken(authRequest.getUsername());
return ResponseEntity.ok(new AuthResponse(jwt));
}
}
10. Managing Logout
Since JWT is managed on the client side, the logout feature can simply be performed by deleting the token on the client. However, it is also possible to implement logout on the server side. For example, maintaining a blacklist to block tokens that have been logged out before expiration can be done.
11. Configuring Middleware
Middleware can be used to add functionality for pre-processing and post-processing requests. For instance, you can check JWT for all requests or restrict access to specific endpoints.
12. Testing and Debugging
Adequate levels of testing should be applied to ensure code quality. Write unit tests for each service, controller, and repository. Spring Boot provides an effective test environment through Junit and Mockito.
13. Conclusion
In this lecture, we took a detailed look at how to implement login and logout using Spring Boot and JWT. JWT is a good method for securely handling communication between client and server, and it can significantly enhance the security of web applications. By understanding this method, you can improve your backend development skills and manage user authentication features more efficiently through such implementations in real projects.