Spring Security - 사용자 인증 중 적절하지 않은 BadCredentialsException 오류

Record For a Better Life ·2023년 4월 30일
0
  public TokenResponse login(String phone, String password) throws CustomException {
    try {
      UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(phone, password);
      Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);
      SecurityContextHolder.getContext().setAuthentication(authentication);
      return tokenProvider.createFrom(authentication);
    } catch (UsernameNotFoundException e) {
      throw new CustomException(MEMBER_NOT_FOUND, "User not found with phone number: " + phone);
    } catch (BadCredentialsException e) {
    throw new CustomException(INVALID_AUTHORITY, "Invalid password");
  }
  }

위와 같이 사용자 인증 시 계정이 존재하지 않으면 UsernameNotFoundException, 단순 비밀번호 오류면 BadCredentialsException e가 뜨게 해놨다.

하지만, 테스트코드를 돌려본 결과 아이디가 없어도, 비밀번호가 틀려도 항상 BadCredentialsException만 떴다.

문제 해결을 위해 사용자의 인증 정보를 확인하는 loadUserByUsername 메소드를 살펴보니,해당 휴대폰 번호로 검색했을 때 결과가 없으면 UsernameNotFoundException을 던지는 부분이 잘 구현되어있다.

  @Override
  public UserDetails loadUserByUsername(String phone_number) throws UsernameNotFoundException {
    // 휴대폰번호(phone_number)을 받아 해당 사용자 정보를 데이터베이스에서 찾아 인증 정보를 제공하는 역할

    User user = userRepository.findOneWithAuthoritiesByPhone(phone_number)
        .orElseThrow(
            () -> new UsernameNotFoundException(String.format("'%s' not found", phone_number)));

문제는 UserDetailsService를 implements한 클래스가 아니라, 스프링 시큐리티의 기본 동작 구조 자체 있었다.

AuthenticationManager는 가장 먼저 인증 처리가 가능한 AuthenticationProvider를 찾은 후 해당 인증을 처리할 수 있는 객체인 AbstractUserDetailsAuthenticationProvider의 authenticate() 메서드를 실행시킨다. 여기서 retrieveUser 메서드가 실행되는데, UsernameNotFoundException이 뜨게 되면 BadCredentialsException을 던졌던 것이다.


서비스단이나 UserDetailsService를 implements했을 때의 문제가 아니라, 구조상 당연한 결과였던 것이다. (이럴 거면 왜 구분해서 설명해놨는지 모르겠지만..)
찾아보니 보안을 위해서 아이디가 틀린 건지 비밀번호가 틀린 건지 알려주지 않기 위해, 두 상황에서 모두 BadCredentialsException을 발생시킨다고 한다. 두 에러 상황을 구분하기 위해서는 Custom class를 만들거나 config 파일을 수정해야 한다.



출처

https://wildeveloperetrain.tistory.com/56
https://theheydaze.tistory.com/307

profile
모든 것을 기록하는 벨로그 💻

0개의 댓글