Next we will be adding the following spring security configuration.
-
1. The userDetailsService() method creates an in-memory user details service and creates a user with the username javainuse and password javainuse. The user is assigned the authority read.
-
2. The passwordEncoder() method creates a BCryptPasswordEncoder bean to encode passwords.
-
3. The filterChain() method configures the security filter chain for HTTP requests. It sets up HTTP basic authentication and authorizes any HTTP request to be authenticated.
So this code configures basic security settings with an in-memory user details service and basic authentication for all HTTP requests.
package com.javainuse.bootmysqlcrud;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class SecurityConfig {
@Bean
UserDetailsService userDetailsService() {
InMemoryUserDetailsManager userDetailsService = new InMemoryUserDetailsManager();
UserDetails user = User.withUsername("javainuse").password(passwordEncoder().encode("javainuse"))
.authorities("read").build();
userDetailsService.createUser(user);
return userDetailsService;
}
@Bean
BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.httpBasic(Customizer.withDefaults());
http.authorizeHttpRequests(auth -> auth.anyRequest().authenticated());
return http.build();
}
}
Let us now look at the how this works for spring security.
No Credentials Provided
Wrong Credentials
Correct Credentials Provided
Next we will be making changes to the the security configuration to create the spring security user using the MySQL database instead of using hard coded values.
Create the DAOUser.
This code defines a class called DAOUser that represents a user entity in a database. The class is annotated with @Entity to indicate that it is a JPA entity and @Table(name = "user") specifies the name of the database table where the entity will be stored.
The class has three fields: id, username, and password. The id field is annotated with @Id and @GeneratedValue(strategy = GenerationType.IDENTITY) which specifies that it is the primary key for the entity and will be generated automatically by the database. The username and password fields are annotated with @Column which indicates that they are columns in the database table.
The class also has getter and setter methods for the username and password fields to allow access to and modification of these values. The password
field is also annotated with @JsonIgnore, which means that it will be ignored during serialization and deserialization, providing an additional layer of
security for sensitive data.
package com.javainuse.bootmysqlcrud.sec;
import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
@Entity
@Table(name = "user")
public class DAOUser {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column
private String username;
@Column
@JsonIgnore
private String password;
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;
}
}
Create the repository interface for the User entity.
-
- It extends JpaRepository, which is a Spring Data interface for performing CRUD operations on the entity.
-
- The entity type for this repository is DAOUser and the primary key type is Integer.
-
- It also includes a custom query method findByUsername, which will return a DAOUser entity based on the given username.
package com.javainuse.bootmysqlcrud.sec;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<DAOUser, Integer> {
DAOUser findByUsername(String name);
}
Next create the Spring service UserDetailsServiceImpl
that implements the UserDetailsService interface. It is used for loading user details by username.
The code first injects the UserRepository dependency using the @Autowired annotation.
Then, it overrides the loadUserByUsername method from the UserDetailsService interface. Inside this method, it retrieves a DAOUser object from the UserRepository using the username passed as a parameter. If the user is not found, it throws a UsernameNotFoundException.
If the user is found, it creates and returns a new User object from the Spring Security core with the username, password, and an empty list of granted authorities. This User object represents the authenticated user.
package com.javainuse.bootmysqlcrud.sec;
import java.util.ArrayList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
DAOUser daoUser = userRepository.findByUsername(username);
if (daoUser == null) {
throw new UsernameNotFoundException("User not found");
}
return new org.springframework.security.core.userdetails.User(daoUser.getUsername(), daoUser.getPassword(),
new ArrayList<>());
}
}
Next modify the SecurityConfig class
-
2. The userDetailsService variable is autowired with an instance of UserDetailsServiceImpl, which is a custom implementation of the Spring
UserDetailsService interface.
-
3. The authenticationProvider method defines a bean of type AuthenticationProvider which is used for authenticating users. It creates a
DaoAuthenticationProvider instance, sets the userDetailsService and passwordEncoder, and returns it.
package com.javainuse.bootmysqlcrud.sec;
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.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class SecurityConfig {
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.httpBasic(Customizer.withDefaults());
http
.csrf(csrf -> csrf.disable()).authorizeHttpRequests(auth -> auth.anyRequest().authenticated());
return http.build();
}
@Bean
public AuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setPasswordEncoder(passwordEncoder());
return authenticationProvider;
}
@Bean
BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Finally go to MySQL database-
If we now try to access the get employees url, the browser asks for credentials. The username and password will be javainuse.
Download Source Code
Download it -
Spring Boot 3 Security Basic Authentication Example