Spring Boot Backend Development Course, Implementing Login and Logout with JWT, Implementing Token Filter

1. Introduction

Spring Boot is a framework that helps you easily develop Java-based web applications. With the recent surge in demand for web applications, understanding security and authentication has become crucial. In this course, we will learn how to implement login and logout functionality using JSON Web Token (JWT) and how to validate JWT tokens through filters. Throughout this course, you will learn how to harness various features of Spring Boot to build a more secure and efficient backend application.

2. What is JWT?

JSON Web Token (JWT) is a JSON-based object used to securely transmit information between two entities. JWT has established itself as a standard not only for user authentication but also for claim-based information transmission. JWT consists of three components:

  • Header: Defines the type of JWT and the hashing algorithm used.
  • Payload: Contains the claim information that is being transmitted.
  • Signature: Created by combining the header and payload and using a secret key. This allows for the verification of JWT’s integrity.

3. Setting Up a Spring Boot Project

To start a Spring Boot project, you need to begin with basic settings. You can use Spring Initializr for these settings. The choices to be made when creating the project are as follows:

  • Project: Maven Project
  • Language: Java
  • Spring Boot: Stable version (Latest)
  • Dependencies: Spring Web, Spring Security, Spring Data JPA, Spring Boot DevTools, H2 Database

Once the project is created, you can open it in your IDE and add the necessary dependencies.

4. Creating Entity Class and Repository

First, we need to define the User entity. A simple User entity is a class that stores user information. This will allow us to interact with the database.

package com.example.demo.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String password;
    
    // Getters and Setters
}

Repositories are needed to perform CRUD operations between entities and the database.

package com.example.demo.repository;

import com.example.demo.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
    User findByUsername(String username);
}

5. Creating Service Class

A service class is needed to handle business logic. This class implements functionalities such as user registration and login.

package com.example.demo.service;

import com.example.demo.entity.User;
import com.example.demo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;
    
    public User register(User user) {
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        return userRepository.save(user);
    }
    
    public User findUserByUsername(String username) {
        return userRepository.findByUsername(username);
    }
}

6. Security Configuration and JWT Creation

You can enhance the application’s security using Spring Security. To do this, you need to create a SecurityConfig class and add a class to generate JWT tokens.

package com.example.demo.config;

import com.example.demo.security.JwtAuthenticationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.annotation.web.configuration.EnableGlobalMethodSecurity;
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 SecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Autowired
    private JwtAuthenticationFilter jwtAuthenticationFilter;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeRequests()
            .antMatchers("/api/auth/**").permitAll()
            .anyRequest().authenticated()
            .and()
            .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

7. Implementing JWT Creation and Verification

Upon logging in, a JWT is generated based on the user’s information and sent to the client. To accomplish this, we create a JWT utility class to handle token generation and verification tasks.

package com.example.demo.security;

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_key";
    private final long EXPIRATION_TIME = 86400000; // 1 day

    public String generateToken(String username) {
        Map<String, Object> claims = new HashMap<>();
        return createToken(claims, username);
    }

    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() + EXPIRATION_TIME))
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
    }

    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 Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody().getExpiration();
    }

    public String extractUsername(String token) {
        return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody().getSubject();
    }
}

8. Implementing Login and Logout Functionality

Now, when a user logs in, they receive a JWT, and during logout, the client deletes the token. Below is an example of the login API.

package com.example.demo.controller;

import com.example.demo.entity.User;
import com.example.demo.security.JwtUtil;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/auth")
public class AuthController {

    @Autowired
    private UserService userService;

    @Autowired
    private JwtUtil jwtUtil;

    @PostMapping("/login")
    public ResponseEntity<String> login(@RequestBody User user) {
        User foundUser = userService.findUserByUsername(user.getUsername());
        if (foundUser != null && passwordEncoder.matches(user.getPassword(), foundUser.getPassword())) {
            return ResponseEntity.ok(jwtUtil.generateToken(foundUser.getUsername()));
        }
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid credentials");
    }

    @PostMapping("/logout")
    public ResponseEntity<String> logout() {
        // The logout functionality is to be implemented on the client-side.
        return ResponseEntity.ok("Successfully logged out.");
    }
}

9. Implementing JWT Filter

It is necessary to implement a JWT filter to validate JWT on all requests and handle authentication. To do this, we create the JwtAuthenticationFilter class.

package com.example.demo.security;

import io.jsonwebtoken.ExpiredJwtException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
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;

public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        String authorizationHeader = request.getHeader("Authorization");

        String username = null;
        String jwt = null;

        if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
            jwt = authorizationHeader.substring(7);
            try {
                username = jwtUtil.extractUsername(jwt);
            } catch (ExpiredJwtException e) {
                System.out.println("JWT is expired");
            }

            if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                UserDetails userDetails = userDetailsService.loadUserByUsername(username);
                if (jwtUtil.validateToken(jwt, userDetails.getUsername())) {
                    UsernamePasswordAuthenticationToken authenticationToken = 
                            new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                    SecurityContextHolder.getContext().setAuthentication(authenticationToken);
                }
            }
        }
        filterChain.doFilter(request, response);
    }
}

10. Conclusion

In this lecture, we learned how to implement login and logout functionality using JWT with Spring Boot. We also explored how to generate and verify JWT tokens and how to enhance application security using Spring Security. Through this course, you will have a foundation for handling authentication and authorization in backend applications more securely. Additionally, you will be able to leverage various features of Spring Boot to develop efficient and secure web applications.

11. References

Spring Boot Backend Development Course, Implementing Login and Logout with JWT, Adding Token Service

Spring Boot is a powerful framework for modern web application development. In this course, we will explain step by step how to implement user authentication using JWT (Json Web Token) and how to achieve login and logout functionality. This process will also cover how to add token services to enhance security and user management features.

1. What is JWT?

JWT is an open standard based on JSON that provides a way to securely transmit information. A JWT consists of three parts: Header, Payload, Signature.

1.1 Header

The Header specifies the type of the JWT and the hashing algorithm. For example:

    {
      "alg": "HS256",
      "typ": "JWT"
    }

1.2 Payload

The Payload contains the user’s information, user ID, expiration time, etc. This part is structured in an easily readable JSON format.

1.3 Signature

The Signature is the value signed with a secret key by combining the encoded Header and Payload. This value guarantees the integrity of the token and is used by the server to validate the token.

2. Project Setup

In this tutorial, we will create a project using Spring Boot and Maven. You can set up the project using IDEs such as IntelliJ IDEA or Eclipse.

2.1 Creating a Maven Project

After creating a Maven project in Eclipse or IntelliJ IDEA, add the following dependencies to the pom.xml file.

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjsonwebtoken</artifactId>
            <version>0.9.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
    </dependencies>

2.2 Spring Security Configuration

Set up basic security configurations using Spring Security. Create a SecurityConfig class and add user authentication and authorization settings.

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    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;

    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/api/auth/**").permitAll()
                .anyRequest().authenticated();
        }
    }
    

3. JWT Creation and Validation

Now we will look at how to create and validate JWTs. Create a JWTUtil class and implement the necessary methods.

    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 String secretKey = "secret";

        public String generateToken(String username) {
            Map<String, Object> claims = new HashMap<>();
            return createToken(claims, username);
        }

        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)) // 10 hours
                    .signWith(SignatureAlgorithm.HS256, secretKey)
                    .compact();
        }

        public Boolean validateToken(String token, String username) {
            final String extractedUsername = extractUsername(token);
            return (extractedUsername.equals(username) && !isTokenExpired(token));
        }

        private String extractUsername(String token) {
            return extractAllClaims(token).getSubject();
        }

        private Claims extractAllClaims(String token) {
            return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody();
        }

        private Boolean isTokenExpired(String token) {
            return extractAllClaims(token).getExpiration().before(new Date());
        }
    }
    

4. Implementing User Authentication and Login API

Now it’s time to implement the user authentication and login API. Create an AuthController class and add the necessary methods.

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.ResponseEntity;
    import org.springframework.security.authentication.AuthenticationManager;
    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    import org.springframework.web.bind.annotation.*;

    @RestController
    @RequestMapping("/api/auth")
    public class AuthController {

        @Autowired
        private AuthenticationManager authenticationManager;

        @Autowired
        private JWTUtil jwtUtil;

        @PostMapping("/login")
        public ResponseEntity<String> login(@RequestBody AuthRequest authRequest) {
            authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(authRequest.getUsername(), authRequest.getPassword())
            );
            final String token = jwtUtil.generateToken(authRequest.getUsername());
            return ResponseEntity.ok(token);
        }
    }

    class AuthRequest {
        private String username;
        private String password;

        // getters and setters
    }
    

5. Implementing Logout API

The logout API is implemented by deleting the JWT token on the client side. A separate logout API is not required, but an example can be added for this part.

6. Adding Token Service

By adding a token service, manage user information and implement functionality to manage user sessions as needed. Create a TokenService class to implement this functionality.

    import org.springframework.stereotype.Service;

    @Service
    public class TokenService {

        @Autowired
        private JWTUtil jwtUtil;

        public String refreshToken(String token) {
            if (jwtUtil.isTokenExpired(token)) {
                String username = jwtUtil.extractUsername(token);
                return jwtUtil.generateToken(username);
            }
            return token;
        }
    }
    

7. Other Considerations and Conclusion

In this course, we explored how to implement login and logout functionality using JWT and add a token service for user authentication. In real applications, additional security measures such as enhancing JWT validation, user permission management, and token storage implementation are required.

8. Conclusion

Implementing a JWT-based authentication system using Spring Boot has become an essential element in enhancing the security of modern web applications. Through this course, you should understand the basic concepts of JWT and the fundamentals of implementing an authentication system using it. Furthermore, try to gain experience in implementing and optimizing various features required for actual projects.

I hope this course helps you with your Spring Boot backend development!

© 2023 Your Blog Name. All rights reserved.

Spring Boot Backend Development Course, Implementing Login and Logout with JWT, Adding a Token Provider

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.

Spring Boot Backend Development Course, Implementing Login and Logout with JWT, What is Token-based Authentication

1. Introduction

In modern web applications, there are various methods to efficiently perform user authentication and authorization management. Among these, JSON Web Token (JWT) is one of the widely used authentication methods. In particular, for backend developers using Spring Boot, JWT can be used to implement login and logout functionalities to create a safer and more efficient user authentication system. This course will explain in detail the concept of JWT, how to implement JWT-based authentication using Spring Boot, and the procedures for login and logout.

2. What is JWT?

JWT stands for JSON Web Token, which is an open standard (RFC 7519) for securely transmitting information between the user and the server. JWT is typically used in the following cases:

  • User authentication
  • Information exchange
  • Authorization

The characteristics of JWT are as follows:

  • It can carry information by itself.
  • It can prevent tampering using a signature.
  • It can be easily used in HTTP transmissions.

JWT consists of three parts: Header, Payload, and Signature. Detailed explanations of each part are as follows.

2.1 Header

The header of a JWT contains two pieces of information: the type of the token and the algorithm used (e.g., HMAC SHA256 or RSA).

{
    "alg": "HS256",
    "typ": "JWT"
}

2.2 Payload

The payload is the second part of the JWT that contains information about the user and claims. Claims can include user information, permissions, and other metadata. For example:

{
    "sub": "1234567890",
    "name": "John Doe",
    "iat": 1516239022
}

In this example, “sub” represents the user’s unique ID, “name” represents the username, and “iat” indicates the time issued.

2.3 Signature

Lastly, the signature is created by combining the header and payload and generating a hash using a secret key. This allows the integrity of the data to be verified. For example:

HMACSHA256(
    base64UrlEncode(header) + "." +
    base64UrlEncode(payload),
    secret)

Through this process, a JWT is generated, and the recipient can verify the validity of the token using the secret key they possess.

3. Spring Boot Setup

To implement a JWT-based user authentication system using Spring Boot, you first need to set up a Spring Boot project. You should create a new project using Spring Initializr and add the necessary dependencies. In this course, we will use Spring Web, Spring Security, and the jjwt library.

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'io.jsonwebtoken:jjwt:0.9.1'
}

4. Configuring Spring Security and JWT

You can set up basic authentication and authorization using Spring Security. To do this, you need to write a SecurityConfig class and define security rules for HTTP requests.

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeRequests()
            .antMatchers("/api/auth/**").permitAll()
            .anyRequest().authenticated()
            .and()
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }
}

In the above configuration, the /api/auth/** route is allowed for all requests, while other requests require authentication. The session management is set to STATLESS to utilize token-based authentication using JWT.

5. User Authentication and JWT Issuance

When a user logs in, the server issues a JWT based on the user’s information. You need to write an AuthController class for user authentication and implement a method to handle login requests.

@RestController
@RequestMapping("/api/auth")
public class AuthController {
    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtProvider jwtProvider;

    @PostMapping("/login")
    public ResponseEntity authenticateUser(@RequestBody LoginRequest loginRequest) {
        Authentication authentication = authenticationManager.authenticate(
            new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));

        SecurityContextHolder.getContext().setAuthentication(authentication);

        String jwt = jwtProvider.generateToken(authentication);
        return ResponseEntity.ok(new JwtResponse(jwt));
    }
}

6. Implementing Logout

Since JWT does not store state values on the server, implementing logout works differently than other methods. Generally, logout is handled by deleting or expiring the JWT on the client side. For example, when the client sends a logout request, the JWT token is deleted, and this token is no longer used for subsequent requests.

@PostMapping("/logout")
    public ResponseEntity logoutUser() {
        // Response handling for client token deletion
        return ResponseEntity.ok(new MessageResponse("User logged out successfully!"));
    }

7. JWT Validation

To validate a JWT on the server, the signature of the token is checked, and the expiration is verified. A JwtProvider can be written for this process.

@Component
public class JwtProvider {
    @Value("${jwt.secret}")
    private String jwtSecret;

    public String generateToken(Authentication authentication) {
        return Jwts.builder()
            .setSubject(authentication.getName())
            .setIssuedAt(new Date())
            .setExpiration(new Date((new Date()).getTime() + 86400000)) // 1 day
            .signWith(SignatureAlgorithm.HS512, jwtSecret)
            .compact();
    }

    public boolean validateToken(String token) {
        try {
            Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}

8. Conclusion

We have seen how to efficiently implement user authentication in Spring Boot using JWT. This token-based authentication method allows for a more flexible application structure without maintaining the server’s state. Based on the content explained in this course, I encourage you to implement a user authentication system using JWT in your projects.

In the future, we will provide you with useful information and courses on various web development topics. Thank you.

Spring Boot Backend Development Course, Implementing Login and Logout with JWT, Implementing Token API

Implementing Login/Logout with JWT and Token API

Recently, the architecture of web applications has become increasingly complex, and security issues are a significant concern for all developers. In this course, we will take a detailed look at how to implement login and logout features based on JWT (JSON Web Token) and the token API using Spring Boot. This course is targeted at developers with basic Spring Boot development experience and includes an understanding of JWT.

Table of Contents

1. What is JWT?

JWT stands for JSON Web Token, an open standard (RFC 7519) for securely transmitting user authentication information. JWT is one of the most commonly used authentication methods, used to prove that a user is logged in without the need to maintain state between the client and server. JWT consists of three parts:

  • Header: Specifies the type of token and the signing algorithm.
  • Payload: Contains user information and claims.
  • Signature: A signature created based on the header and payload.

One of the main advantages of JWT is that it allows for stateless authentication. This means that the server does not store session information, thereby reducing the server’s burden and making it easier to scale out.

2. Project Setup

Before starting the project, you need to create a Spring Boot project. You can easily set up a project using Spring Initializr. Add the following dependencies:

  • Spring Web
  • Spring Security
  • Spring Data JPA
  • H2 Database (or any database of your choice)
  • jjwt (Java JWT library)

After creating the project, add the necessary libraries to your `pom.xml`:



    
    
        io.jsonwebtoken
        jjwt
        0.9.1
    


3. User Authentication and JWT Issuance

To authenticate users, create a User entity and UserRepository. Then, set up the service layer and implement the logic to generate JWT.


// Example of User Entity
@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String username;
    private String password;
    
    // getters and setters
}


// Example of UserRepository
public interface UserRepository extends JpaRepository {
    Optional findByUsername(String username);
}

Now, let’s add the functionality to create JWT:


// JwtUtil.java
@Component
public class JwtUtil {
    
    private String secretKey = "secret"; // In production, manage this in environment variables or separate files
    
    public String generateToken(String username) {
        return Jwts.builder()
                    .setSubject(username)
                    .setIssuedAt(new Date(System.currentTimeMillis()))
                    .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) // 10 hours
                    .signWith(SignatureAlgorithm.HS256, secretKey)
                    .compact();
    }
}

3.1 Implementing Login API

Now we will implement a Controller to handle login requests:


// AuthController.java
@RestController
@RequestMapping("/api/auth")
public class AuthController {
    
    @Autowired
    private AuthenticationManager authenticationManager;
    
    @Autowired
    private JwtUtil jwtUtil;
    
    @Autowired
    private UserRepository userRepository;
    
    @PostMapping("/login")
    public ResponseEntity login(@RequestBody User user) {
        authenticate(user.getUsername(), user.getPassword());
        String token = jwtUtil.generateToken(user.getUsername());
        return ResponseEntity.ok(token);
    }
    
    private void authenticate(String username, String password) {
        Authentication authentication = authenticationManager.authenticate(
            new UsernamePasswordAuthenticationToken(username, password)
        );
        SecurityContextHolder.getContext().setAuthentication(authentication);
    }
}

4. Token Verification and Authorization

To handle authenticated requests using JWT, you need to implement a filter to validate the token in the request header.


// JwtRequestFilter.java
@Component
public class JwtRequestFilter extends OncePerRequestFilter {

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private UserDetailsService userDetailsService;

    @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) {
            UserDetails userDetails = userDetailsService.loadUserByUsername(username);
            if (jwtUtil.validateToken(jwt, userDetails)) {
                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
                        new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            }
        }
        chain.doFilter(request, response);
    }
}

5. Implementing Logout Functionality

Since JWT is stateless, implementing logout functionality means that the client simply deletes the token. However, it is also possible to implement logout functionality by managing a blacklist on the server.


// Example of Logout
@PostMapping("/logout")
public ResponseEntity logout(HttpServletRequest request) {
    String token = request.getHeader("Authorization").substring(7);
    // Implement logic to add to blacklist here
    return ResponseEntity.ok("Logout successful");
}

6. API Testing

You can test the API using tools like Postman. After the login request, confirm that you can access protected resources using the JWT issued by the server.

7. Conclusion

In this course, we learned how to implement a JWT-based authentication system using Spring Boot. Depending on the system requirements, JWT can be utilized in various ways, and security should always remain a key consideration. Going forward, consider adding more advanced features to expand the system.