Home > Software design >  Custom UserDetailsService is not called by spring-boot
Custom UserDetailsService is not called by spring-boot

Time:09-26

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?

CodePudding user response:

Your problem seems to be with CSRF rather than with UserDetailsService's implementation not being registered, Starting from Spring 4.x, CSRF protection is enabled by default and unless you turn it off like

http
    .csrf()
    .disable()

you are going to get 403 errors.

  • Related