Spring Boot 3.0 Security with InMemory DB Users
when you are working with Spring Boot 3.0 security hence working with spring security 5 and above modules there are few changes you have to understand while moving from older module version like spring security 3.0 and 4.0.
let’s understand these changes and also understand working with them using InMemory DB to create an user.
NOTE : you can find my other blogs to understand how to work with DBMS software.
to work with spring boot 3.0 security you have to use below spring boot starter.
<!-- You can use any Spring Boot 3 version-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>3.0.2</version>
</dependency>
with the use of above dependency spring boot by default use the form based authentication with username as user and password present in application startup logs.
if don’t want to use the default username and password you can use the below configs in application.properties file to configure the desired username and password.
# to change default username and password.
spring.security.user.name = user
spring.security.user.password = password
so if you now start your application and try to hit any api’s from browser then it will show you one login page and you can use above username and password to login successfully.
Changes in Old and New Version
now let’s understand the different configs which is the main focus for our blog.
in older spring security versions we had to create a config class , annotate the class with @EnableWebSecurity annotation and extend our config class with WebSecurityConfigurerAdaptor class to override some of it’s method to perform the desired configuration like overriding the configure(-) method .
you can check below code for old implementation.
// Old Approach
@Configuration
@EnableWebSecurity
class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "/public/**").permitAll()
.antMatchers("/users/**").hasRole("ADMIN")
.anyRequest()
.authenticated()
.and()
.httpBasic()
}
}
In Spring Boot 3.0 security the way above code is implemented changes a lot.
WebSecurityConfigurerAdaptor is depricated. we no longer need to override configure method and lot of HttpSecurity methods are depricated like authorizeRequests() etc.
let’s understand how we can proceed now.
In Spring boot 3.0 security we no longer need to extend our class with WebSecurityConfigurereAdaptor we can use only @EnableWebSecurity and with we have to create few @Bean annotated method
if we want to make configure HttpSecurity object we have to write @Bean method for the same, the example for it is as below.
//New Approach (Spring Boot 3.0 Security)
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http.csrf().disable()
.authorizeHttpRequests()
.requestMatchers("/emps/**")
.permitAll()
.and()
.authorizeHttpRequests()
.requestMatchers("/user/create")
.hasAnyRole("ADMIN")
.and()
.httpBasic()
.and()
.build();
}
}
Here you can see instead of authorizeRequests() we using authorizeHttpRequests(), instead of antMatcher() we are using requestMatcher() which internally uses antMatcher() only for the rest most of the things are same as previous approaches.
Endpoint Method Level Security
In older spring security approach we used to annotate the config class with @EnableGlobalMethodSecurity annotation which is now depricated and we now use @EnableMethodSecurity annotation
now once we annotate configure class with @EnableMethodSecurity annotation we just need to has @hasAuthority annotation on top of endpoint method like old approach and we are good to go.
you can follow bellow example
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
@PostMapping(value = "/create", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<EmployeeModel> addUser(@RequestBody @Valid UserModel user){
UserModel savedUser = userService.addUser(user);
return new ResponseEntity(savedUser,HttpStatus.CREATED);
}
InMemory DB User Creation
To add InMemory DB use to test the spring security configs you have to create a @Bean annotated method which will return one of the instance of UserDetailsService class in our class InMemoryUserDetailsManager and we good to go.
@Bean
public InMemoryUserDetailsManager userDetailsService() {
UserDetails user = User.withUsername("user")
.password(passwordEncoder().encode("password"))
.roles("USER")
.build();
UserDetails admin = User.withUsername("admin")
.password(passwordEncoder().encode("admin"))
.roles("USER", "ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
the choice of encoder to encode the password can be your choice you can use BCryptPasswordEncoder or other encoders as per your usecase.
I’m providing one such example with NoOpPasswordEncoder which is now depricated but can be used for testing purpose.
@Bean
public PasswordEncoder passwordEncoder() {
PasswordEncoder encoder = NoOpPasswordEncoder.getInstance();
return encoder;
}