I'm trying to use UserDetailsService in spring-security to implement my authentication logic. However, UserDetailsService is not called during an HTTP request. Here is the code:
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserService userService;
@Override
public UserDetails loadUserByUsername(String userId) throws UsernameNotFoundException {
Optional<User> user = userService.getById(Long.parseLong(userId));
if (user.isEmpty()) {
throw new UsernameNotFoundException("User " + userId + " not found");
}
return new org.springframework.security.core.userdetails.User(
user.get().getName(),
user.get().getHashedPassword(),
List.of());
}
}
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailsService customUserDetailsService;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
protected void configure(HttpSecurity http) throws Exception { // (2)
http.authorizeRequests()
.antMatchers("/user/add", "/user/loginByEmail").permitAll() // (3)
.anyRequest().authenticated()
.and()
.logout()
.permitAll()
.and()
.httpBasic();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailsService)
.passwordEncoder(passwordEncoder);
}
}
I use a test to test the authentication logic, here is the core of the test code:
MvcResult addMvcResult = mockMvc.perform(post("/habit/friend/addById")
.with(SecurityMockMvcRequestPostProcessors.httpBasic("Joey", "password"))
.contentType("application/json")
.content(StringUtils.toJSONString(addFriendRequestByIdDTO)))
.andExpect(status().isOk())
.andReturn();
The log shows that the authentication header is inserted by spring-test:
MockHttpServletRequest:
HTTP Method = POST
Request URI = /habit/friend/addById
Parameters = {}
Headers = [Content-Type:"application/json;charset=UTF-8", Content-Length:"47", Authorization:"Basic Sm9leTpwYXNzd29yZA=="]
Body = {
"currentUserId" : 1,
"friendUserId" : 2
}
Session Attrs = {org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN=org.springframework.security.web.csrf.DefaultCsrfToken@3a48c398}
However, the authentication failed, I got a 403, and CustomUserDetailsService is never called. Why?