Table of Contents
- Introduction
- Project Setup
- Setting up Spring Boot Application
- Adding Dependencies
- Database Setup (MySQL)
- Setting Up MySQL Database
- Configuring MySQL Connection in Spring Boot
- Creating the User Model & Repository
- JWT Authentication
- Creating JWT Utility Class
- JWT Filter
- Configuring Security Configuration
- User Registration and Login
- Registration API
- Login API
- Implementing CRUD Operations
- Create, Read, Update, Delete Operations
- Exception Handling
- Testing the API
- Conclusion
1. Introduction
In this project, you will build a simple but powerful RESTful CRUD API using Spring Boot, JWT (JSON Web Token) for secure authentication, and MySQL as the relational database. This project will help you understand how to create secure, efficient, and scalable web services. By the end of the project, you will have a complete Spring Boot application with JWT authentication and basic CRUD functionality.
2. Project Setup
Setting up Spring Boot Application
First, create a new Spring Boot project using your preferred IDE (e.g., IntelliJ IDEA or Spring Tool Suite). You can also use Spring Initializr to generate a base project.
- Group:
com.example
- Artifact:
jwtcrudapi
- Dependencies: Spring Web, Spring Data JPA, Spring Security, MySQL Driver, Lombok (optional), JWT (for token-based authentication)
pom.xml (Maven) Configuration Example:
xmlCopyEdit<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<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>com.mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.11.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
</dependencies>
Adding Dependencies
Ensure the necessary dependencies are added in the pom.xml
or build.gradle
. The required dependencies are:
- Spring Boot Web: For building RESTful APIs.
- Spring Data JPA: For ORM and database interaction.
- Spring Security: For securing the application using JWT.
- JWT: For generating and validating JSON Web Tokens.
- MySQL: For the database connection.
3. Database Setup (MySQL)
Setting Up MySQL Database
You need a MySQL database to store user data. Here’s how to set it up:
- Install MySQL on your system or use a managed MySQL service.
- Create a Database: sqlCopyEdit
CREATE DATABASE jwtcrudapi;
- Create a User Table: sqlCopyEdit
CREATE TABLE users ( id BIGINT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(255) UNIQUE NOT NULL, password VARCHAR(255) NOT NULL, role VARCHAR(50) NOT NULL );
Configuring MySQL Connection in Spring Boot
In the application.properties
or application.yml
, configure the database connection settings:
propertiesCopyEditspring.datasource.url=jdbc:mysql://localhost:3306/jwtcrudapi
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
4. Creating the User Model & Repository
Create the User entity to map to the users
table and the corresponding JPA repository.
User Entity (User.java
)
javaCopyEdit@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true)
private String username;
private String password;
private String role; // e.g., "ROLE_USER"
// Getters and Setters
}
User Repository (UserRepository.java
)
javaCopyEditpublic interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByUsername(String username);
}
5. JWT Authentication
In this section, we will create the necessary classes to handle JWT-based authentication.
JWT Utility Class (JwtUtils.java
)
This utility class will handle JWT creation and validation.
javaCopyEdit@Component
public class JwtUtils {
private String jwtSecret = "secretKey"; // This should be in properties
public String generateJwtToken(Authentication authentication) {
UserPrincipal userPrincipal = (UserPrincipal) authentication.getPrincipal();
return Jwts.builder()
.setSubject(userPrincipal.getUsername())
.setIssuedAt(new Date())
.setExpiration(new Date((new Date()).getTime() + 86400000)) // 1 day expiry
.signWith(SignatureAlgorithm.HS512, jwtSecret)
.compact();
}
public String getUsernameFromJwtToken(String token) {
return Jwts.parser()
.setSigningKey(jwtSecret)
.parseClaimsJws(token)
.getBody()
.getSubject();
}
public boolean validateJwtToken(String authToken) {
try {
Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken);
return true;
} catch (JwtException e) {
return false;
}
}
}
JWT Filter (JwtAuthenticationFilter.java
)
This filter will intercept each request to validate the JWT token.
javaCopyEditpublic class JwtAuthenticationFilter extends OncePerRequestFilter {
private JwtUtils jwtUtils;
public JwtAuthenticationFilter(JwtUtils jwtUtils) {
this.jwtUtils = jwtUtils;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String jwt = getJwtFromRequest(request);
if (StringUtils.hasText(jwt) && jwtUtils.validateJwtToken(jwt)) {
String username = jwtUtils.getUsernameFromJwtToken(jwt);
// Set Authentication for Security Context
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>());
SecurityContextHolder.getContext().setAuthentication(authentication);
}
filterChain.doFilter(request, response);
}
private String getJwtFromRequest(HttpServletRequest request) {
String header = request.getHeader("Authorization");
if (StringUtils.hasText(header) && header.startsWith("Bearer ")) {
return header.substring(7);
}
return null;
}
}
Security Configuration (WebSecurityConfig.java
)
javaCopyEdit@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private JwtUtils jwtUtils;
@Autowired
public WebSecurityConfig(JwtUtils jwtUtils) {
this.jwtUtils = jwtUtils;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/auth/**").permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(new JwtAuthenticationFilter(jwtUtils), UsernamePasswordAuthenticationFilter.class);
}
}
6. User Registration and Login
Registration API (AuthController.java
)
javaCopyEdit@RestController
@RequestMapping("/auth")
public class AuthController {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private JwtUtils jwtUtils;
@Autowired
private UserRepository userRepository;
@PostMapping("/register")
public ResponseEntity<String> registerUser(@RequestBody User user) {
// Validate user data, save to DB
userRepository.save(user);
return ResponseEntity.ok("User registered successfully");
}
@PostMapping("/login")
public ResponseEntity<?> authenticateUser(@RequestBody LoginRequest loginRequest) {
// Authenticate user and generate JWT token
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword())
);
String jwt = jwtUtils.generateJwtToken(authentication);
return ResponseEntity.ok(new JwtResponse(jwt));
}
}
7. Implementing CRUD Operations
Now, you can implement the CRUD operations. For simplicity, let’s create a Product resource that the user can interact with.
Product Model (Product.java
)
javaCopyEdit@Entity
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private Double price;
// Getters and Setters
}
Product Repository (ProductRepository.java
)
javaCopyEditpublic interface ProductRepository extends JpaRepository<Product, Long> {
}
Product Controller (ProductController.java
)
javaCopyEdit@RestController
@RequestMapping("/products")
public class ProductController {
@Autowired
private ProductRepository productRepository;
@GetMapping
public List<Product> getAllProducts() {
return productRepository.findAll();
}
@PostMapping
public Product createProduct(@RequestBody Product product) {
return productRepository.save(product);
}
@PutMapping("/{id}")
public ResponseEntity<Product> updateProduct(@PathVariable Long id, @RequestBody Product productDetails) {
Product product = productRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Product not found"));
product.setName(productDetails.getName());
product.setPrice(productDetails.getPrice());
productRepository.save(product);
return ResponseEntity.ok(product);
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteProduct(@PathVariable Long id) {
Product product = productRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Product not found"));
productRepository.delete(product);
return ResponseEntity.noContent().build();
}
}
8. Exception Handling
Add a centralized exception handler using @ControllerAdvice
to handle errors globally.
javaCopyEdit@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<?> handleResourceNotFound(ResourceNotFoundException ex) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
}
}
9. Testing the API
You can test the API using tools like Postman or Swagger. For instance:
- Register User:
POST /auth/register
- Login User:
POST /auth/login
- CRUD Operations:
GET /products
,POST /products
,PUT /products/{id}
,DELETE /products/{id}
10. Conclusion
This project demonstrates how to build a secure RESTful API with Spring Boot, JWT for authentication, and MySQL for data storage. By using JWT, we ensure stateless and secure authentication for the API. This can be the foundation for more advanced applications that require secure user authentication and CRUD operations.