I have injected my userrepo with @Autowired. I can signup and add users to the database without any problem. However when I have to authenticate against users in my database I get this issue
Caused by: java.lang.NullPointerException: Cannot invoke "com.workout.befit.repository.UserRepo.findByUsername(String)" because "this.userrepo" is null
at com.workout.befit.services.CustomUserDetails.loadUserByUsername(CustomUserDetails.java:29) ~[classes/:na]
at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:107) ~[spring-security-core-6.4.2.jar:6.4.2]
this is my repo
package com.workout.befit.repository;
import org.springframework.data.mongodb.repository.MongoRepository;
import com.workout.befit.models.User;
import java.util.Optional;
public interface UserRepo extends MongoRepository<User, String> {
Optional<User> findByUsername(String username);
}
this is my security config
package com.workout.befit.utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
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.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import com.workout.befit.services.CustomUserDetails;
@Configuration
@EnableWebSecurity
@ComponentScan
public class SecurityConfig {
@Autowired
@Qualifier("customuserdetails")
CustomUserDetails customuserdetails;
@Autowired
PasswordEncoder passencoder;
@Autowired
AuthenticationProvider authprovider;
@Bean
public SecurityFilterChain securityFilterchain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize->authorize.requestMatchers("/signup","/about","/error/**").permitAll() //allow requests to signup page
.anyRequest().authenticated()) //authenticate all other requests
.httpBasic(Customizer.withDefaults())
.formLogin(Customizer.withDefaults())
.csrf(csrf-> csrf.disable());
return http.build();
}
}
this is my security bean
package com.workout.befit.utils;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import com.workout.befit.services.CustomUserDetails;
@Component
public class Securitybeans {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();}
@Bean
public UserDetailsService customuserdetailsservice(){
return new CustomUserDetails();
}
@Bean
public AuthenticationProvider authprovider(){
DaoAuthenticationProvider provider=new DaoAuthenticationProvider();
provider.setPasswordEncoder(passwordEncoder());
provider.setUserDetailsService(customuserdetailsservice());
return provider;
}
}
this is my custom user details service
package com.workout.befit.services;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.security.core.userdetails.User.UserBuilder;
import org.springframework.security.crypto.password.PasswordEncoder;
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;
import com.workout.befit.models.User;
import com.workout.befit.repository.UserRepo;
@Service("customuserdetails")
public class CustomUserDetails implements UserDetailsService {
@Autowired
UserRepo userrepo;
@Autowired
PasswordEncoder bcrypt;
@SuppressWarnings("null")
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Optional<User> optionaluser=userrepo.findByUsername(username);
User user=optionaluser.orElseThrow();
UserBuilder builder = null;
builder.username(user.getUsername());
builder.password(bcrypt.encode(user.getPassword()));
builder.authorities(user.getAuthorities());
return builder.build();
}
}
It says that this.userrepo in customuserdetailsservice is null therefore it can't call find by name function.
Try adding this in your code instead of using field level bean creation, use constructor based bean creation for the UserRepo in CustomerDetails class like mentioned by @M.Deinum
import lombok.RequiredArgsConstructor;
@Service("customuserdetails")
@RequiredArgsConstructor
public class CustomUserDetails implements UserDetailsService {
private final UserRepo userrepo;
private final PasswordEncoder bcrypt;
// rest of the code
}
and add the @Configuration annotation instead of @Component to SecurityBeans class
import org.springframework.context.annotation.Configuration;
@Configuration
public class Securitybeans {
//rest of the code
}