개발공부/spring security & JWT 강의

[4강] 스프링 시큐리티 로그인 구현 - '?error' 발생

기억지기 개발자 2023. 9. 20. 16:13

🏕️상황

  • 강의를 따라 하던 중에 회원가입은 정상적으로 작동했으나 '로그인'에서 로그인이 되지 않고 아래의 사진처럼 오류가 발생했다.
  • 미쳐버릴 지경이었다. 
    콘솔에는 아무런 오류도 찍히지 않고, 심지어 두 번째 사진처럼 사용자 정보도 굉장히 잘 찾아지는데 왜 로그인만 안 되는지 답답하고, 막막했다. 진짜로 두 번째 사진처럼 콘솔에는 아무런 오류도 없었다.

 

실제 URL 화면 캡쳐
실제 콘솔 캡쳐

 


 

💦과정

1. 관련이 있는 클래스들을 돌아다니며 코드를 수정해보았지만 무용지물....

 

2. WebSecurityConfigurerAdapter의 deprecated로 인한 코드 수정....

  • 강의에서는 WebSecurityConfigurerAdapter를 사용하여 코드상에 해당 부분에 줄이 그어져 있는(deprecated) 상황이었다.
  • 그래서 검색해보니 인프런에서 알려준 방법을 사용하는 것이 최신 버전인 거 같아서 내 코드와 합쳐 수정해 보았다.
  • 더 나은 방향으로 진행한 것은 맞지만 에러가 해결되지는 않았다.

출처 : 인프런 커뮤니티
왼쪽이 강의에 따라 WebSecurityConfigurerAdapter를 사용한 쪽 / 오른쪽이 블로그를 참고하여 수정한 쪽

 

3. 에러에 대응하는 핸들러 클래스를 만들어 원인 찾아보기

@Component
public class UserLoginFailHandler extends SimpleUrlAuthenticationFailureHandler {

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
                                        AuthenticationException exception) throws IOException, ServletException {

        String errorMessage;
        if (exception instanceof BadCredentialsException) {
            errorMessage = "아이디 또는 비밀번호가 맞지 않습니다. 다시 확인해 주세요.";
        } else if (exception instanceof InternalAuthenticationServiceException) {
            errorMessage = "내부적으로 발생한 시스템 문제로 인해 요청을 처리할 수 없습니다. 관리자에게 문의하세요.";
        } else if (exception instanceof UsernameNotFoundException) {
            errorMessage = "계정이 존재하지 않습니다. 회원가입 진행 후 로그인 해주세요.";
        } else if (exception instanceof AuthenticationCredentialsNotFoundException) {
            errorMessage = "인증 요청이 거부되었습니다. 관리자에게 문의하세요.";
        } else {
            errorMessage = "알 수 없는 이유로 로그인에 실패하였습니다 관리자에게 문의하세요.";
        }

        errorMessage = URLEncoder.encode(errorMessage, "UTF-8");
        setDefaultFailureUrl("/auth/loginForm?error=true&exception=" + errorMessage);

        super.onAuthenticationFailure(request, response, exception);
    }
}
  • 하지만 슬프게도 (아래의 사진처럼) 맨 마지막 오류 메시지가 나왔다. 
  • 그 말은 즉, 또 원인을 정확히 파악할 수 없는 말이다.

실제 오류 url

 

 이렇게 했을 때 오류를 잡지는 못했다...  실패....

 

 


 

🗝️해결

그런데 자세히 생각해 보니 해결의 방법을 찾을 수 있었다.

  • 오류 핸들러를 작성하니 맨 처음에 있던 오류 url보다 한 단계 더 자세하게 나와있게 되었고, /auth/라는 경로가 나와있었다.
  • 그래서!! auth라는 폴더 경로 아래에 있는 클래스 중에 하나가 문제라고 생각이 들었고, 그 파일들만 분석해 보게 되었다.

// PrincipalDetailsService 클래스

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    System.out.println("username : " + username);
    User user = userRepository.findByUsername(username);
    if (user == null) {
        throw new UsernameNotFoundException("사용자를 찾을 수 없습니다: " + username);
    }
    
    // 사용자 정보를 UserDetails 객체로 변환
    return new org.springframework.security.core.userdetails.User(
        user.getUsername(),
        user.getPassword(),
        // 권한 설정 (필요에 따라 변경)
        Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"))
    );
}
  • 1차적으로 이렇게 코드를 구성했을 때 로그인에 성공할 수 있었다...
  • 하지만 UserDetails를 구현한 클래스를 저렇게 생짜로 return 값으로 주는 것은 말이 안 된다고 생각하여 근본적인 원인을 찾으려고 했다.

  • 이미 이렇게 UserDetails를 구현한 클래스가 존재하는데... 이 클래스를 반드시 활용하면서도 성공할 방법을 고민하였다.

UserDetails를 구현한 클래스에 @Data를 붙이지 않아서 로그인이 그렇게 지독하게 되지 않았던 것이다...