에러 메시지 :

java.lang.ClassCastException: class java.lang.String cannot be cast to class com.linked.classbridge.dto.user.CustomOAuth2User (java.lang.String is in module java.base of loader 'bootstrap'; com.linked.classbridge.dto.user.CustomOAuth2User is in unnamed module of loader 'app')

원인 :

Authentication 객체의 getPrincipal() 메소드가 CustomOAuth2User 객체 대신 문자열을 반환하기 때문에 발생. 일반적으로 Authentication 객체가 아직 완전히 인증되지 않았거나, 인증 과정에서 문제가 발생했을 때 발생.

회원가입(/signup)요청 시 필요한 UserDTO를 반환해주는 loadUser 메소드는 Spring Security의 인증 과정 중에 호출되며, 그 결과는 Authentication 객체의 Principal로 설정됨. 따라서 사용자가 아직 등록되지 않은 상태인 추가 정보 입력 단계에서는 Authentication 객체에서 UserDTO를 받을 수 없음.

해결 방법 :

세션에 UserDTO 넣어두고 controller에서 호출하도록 코드 변경

변경 전 :

    @PostMapping("/auth/signup")
    public ResponseEntity<SuccessResponse<?>> signup(@RequestBody AuthDTO.SignUp signupRequest) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null && authentication.getPrincipal() instanceof CustomOAuth2User) {
            CustomOAuth2User user = (CustomOAuth2User) authentication.getPrincipal();
            UserDTO userDTO = user.getUser();
            signupRequest.setUserDTO(userDTO);
        }
        userService.addUser(signupRequest);
        return ResponseEntity.status(CREATED).body(
                SuccessResponse.of("user created successfully")
        );
    }
    @Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {

        String registrationId = userRequest.getClientRegistration().getRegistrationId();
        String accessToken = userRequest.getAccessToken().getTokenValue();

        if (registrationId.equals("google")) {
            // Google API 호출
            RestTemplate restTemplate = new RestTemplate();
            HttpHeaders headers = new HttpHeaders();
            headers.setBearerAuth(accessToken);
            HttpEntity<String> entity = new HttpEntity<>(headers);

            ResponseEntity<GoogleResponse> response = restTemplate.exchange(
                    "<https://www.googleapis.com/oauth2/v1/userinfo>",
                    HttpMethod.GET,
                    entity,
                    GoogleResponse.class
            );

            GoogleResponse googleResponse = response.getBody();

            Optional<User> existingUserOptional = userRepository.findByEmail(googleResponse.getEmail());
            if (existingUserOptional.isPresent()) {
                User existingUser = existingUserOptional.get();
                if (existingUser.getAuthType() != AuthType.GOOGLE) {
                    throw new RestApiException(ALREADY_REGISTERED_OTHER_AUTH_TYPE);
                } else {
                    UserDTO userDTO = new UserDTO();
                    userDTO.setProvider(existingUser.getProvider());
                    userDTO.setProviderId(existingUser.getProviderId());
                    userDTO.setEmail(existingUser.getEmail());
                    userDTO.setUsername(existingUser.getUsername());
                    userDTO.setAuthType(existingUser.getAuthType());

                    // List<UserRole> 에서 List<String> 로 변환, "ROLE_" prefix 제거
                    List<String> roles = existingUser.getRoles().stream()
                            .map(role -> role.name().substring(5))
                            .collect(Collectors.toList());
                    userDTO.setRoles(roles);

                    return new CustomOAuth2User(userDTO); // // Spring Security의 인증 객체(Authentication)에 저장
                }
            } else {
                UserDTO userDTO = new UserDTO();
                userDTO.setProvider(googleResponse.getProvider());
                userDTO.setProviderId(googleResponse.getProviderId());
                userDTO.setEmail(googleResponse.getEmail());
                userDTO.setUsername(googleResponse.getName());
                userDTO.setAuthType(AuthType.GOOGLE);
                userDTO.setRoles(Collections.singletonList("USER"));

                return new CustomOAuth2User(userDTO);
            }
        } else {
            throw new RestApiException(NOT_SUPPORTED_AUTH_TYPE);
        }
    }