카카오톡 로그인 에러 문의드립니다!

안녕하세요 현재 REST API로 카카오톡 로그인을 구현하고 있습니다.

Spring Security와 OAuth2-Client를 통해 Spring 환경에서 인가 코드를 받아 서버에 회원 정보를 저장하고, JWT를 발급하여localhost:3000/login/oauth2/success 로 리다이렉트 시켜주는 로직을 구현하고 배포하였습니다.

로컬 서버 환경과(localhost:8080)과 브라우저 환경에서 로그인 테스트를 했을 때는 잘 작동하는데,
로컬 리액트 환경에서 {배포 주소}/oauth2/authorization/kakao로 요청 후 카카오톡 로그인 진행하면
자꾸 {배포 주소}/oauth2/code/kakao/에서 넘어가지 않고에러가 발생합니다…

Spring Security 설정에 문제가 있는 걸까요?
브라우저에서는 잘 되지만 로컬 리액트에서는 에러가 나는 이유가 궁금합니다 ㅠ
앱 ID 933037

이건 리액트 에러 캡쳐 사진입니다

package com.dansup.server.config.security;

import com.dansup.server.config.jwt.JwtAuthenticationFilter;
import com.dansup.server.config.oauth.CustomOAuth2UserService;
import com.dansup.server.config.oauth.OAuth2AuthenticationFailureHandler;
import com.dansup.server.config.oauth.OAuth2AuthenticationSuccessHandler;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.List;

@Configuration
@RequiredArgsConstructor
@EnableWebSecurity
public class SecurityConfig {

    private final JwtAuthenticationFilter jwtAuthenticationFilter;
    private final OAuth2AuthenticationSuccessHandler oAuth2AuthenticationSuccessHandler;

    private final OAuth2AuthenticationFailureHandler oAuth2AuthenticationFailureHandler;
    private final CustomOAuth2UserService customOAuth2UserService;

    private static final String[] swagger = {
            "/v2/api-docs",
            "/swagger-resources/**",
            "/swagger-ui.html",
            "/swagger/**",
            "/webjars/**"
    };

    @Bean
    public SecurityFilterChain configure(HttpSecurity httpSecurity) throws Exception {

        return httpSecurity
                .cors().configurationSource(corsConfigurationSource())

                .and()
                .formLogin().disable()
                .httpBasic().disable()
                .csrf().disable()
                .headers().frameOptions().disable()

                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)

                .and()
                .authorizeRequests()
                .antMatchers(swagger).permitAll()
                .antMatchers(HttpMethod.GET, "/danceclasses/**").permitAll()
                .antMatchers(HttpMethod.GET,"/profile/**").permitAll()
                .antMatchers("/login/**").permitAll()
                .anyRequest().authenticated()

                .and()
                .exceptionHandling()
                .accessDeniedHandler(new CustomAccessDeniedHandler())
                .authenticationEntryPoint(new CustomAuthenticationEntryPoint())

                .and()
                .oauth2Login()
                .successHandler(oAuth2AuthenticationSuccessHandler)
                .failureHandler(oAuth2AuthenticationFailureHandler)
                .userInfoEndpoint()
                .userService(customOAuth2UserService)
                .and()

                .and()
                .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
                .build();

    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration config = new CorsConfiguration();
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

        config.setAllowCredentials(true);
        config.addAllowedOriginPattern("*");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        config.setExposedHeaders(List.of("*"));

        source.registerCorsConfiguration("/**", config);
        return source;
    }

}

package com.dansup.server.config.oauth;

import com.dansup.server.api.user.domain.User;
import com.dansup.server.api.user.domain.UserRole;
import com.dansup.server.api.user.repository.UserRepository;
import com.dansup.server.common.exception.BaseException;
import com.dansup.server.common.response.ResponseCode;
import com.dansup.server.config.security.CustomUserDetails;
import com.dansup.server.config.jwt.JwtTokenProvider;
import com.dansup.server.config.jwt.dto.JwtTokenDto;
import com.dansup.server.config.jwt.refresh.RefreshTokenService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
@Slf4j
@RequiredArgsConstructor
public class OAuth2AuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {

    private final JwtTokenProvider tokenProvider;
    private final RefreshTokenService refreshTokenService;

    private final UserRepository userRepository;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                                        Authentication authentication) throws IOException {

        CustomUserDetails oAuth2User = (CustomUserDetails) authentication.getPrincipal();

        String targetUrl = null;

        JwtTokenDto jwtTokenDto = tokenProvider.createJwtToken(oAuth2User.getName());
        refreshTokenService.saveRefreshToken(jwtTokenDto.getRefreshToken(), oAuth2User.getName());

        targetUrl = UriComponentsBuilder
                .fromUriString(setSuccessRedirectUrl(request.getServerName(), request.getServerPort()))
                .queryParam("accessToken", jwtTokenDto.getAccessToken())
                .queryParam("refreshToken", jwtTokenDto.getRefreshToken())
                .queryParam("isGuest", isGuest(oAuth2User.getName()))
                .build()
                .toUriString();

        log.info("[targetUrl]: {}", targetUrl);
        getRedirectStrategy().sendRedirect(request, response, targetUrl);

    }

    private String setSuccessRedirectUrl(String requestUrl, int requestPort) {
        String redirectUrl = null;

        log.info("[Request URL]: {}, {}", requestUrl, requestPort);

        if(requestUrl.equals("localhost") && requestPort == 8080) {
            redirectUrl = "http://localhost:8080/login/oauth2/success";
        }
        if(requestUrl.equals("localhost") && requestPort == 3000) {
            redirectUrl = "http://localhost:3000/login/oauth2/success";
        }
        if (requestUrl.equals("takgyun.shop")) {
            redirectUrl = "http://localhost:3000/login/oauth2/success";
        }

        return redirectUrl;
    }

    private boolean isGuest(String email) {
        User user = userRepository.findByEmail(email).orElseThrow(
                () -> new BaseException(ResponseCode.USER_NOT_FOUND)
        );

        return user.getUserRole().equals(UserRole.ROLE_GUEST);
    }

}


안녕하세요.

참부 이미지의 두번째 주소호출에 붉은 링크 리다이렉트 URL 어떤 에러 발생했는지 서버로그 먼저 공유 부탁드립니다.

https://takgyun.shop/login/oauth2/code/kakao?code={인가코드}

카카오측에 해당 디벨로퍼스앱 로그상 에러가 없는 것을 보면 개발하신 서버 내부 문제일듯해요.

OAuth2AuthenticationFailureHandler가 작동하면서 에러가 생깁니다!

이건 nginx 로그입니다!

esQik0로 시작하는 인가코드관련 흐름 살펴봤습니다.

(1) /oauth/authorize , 리다이렉트 https://takgyun.shop/login/oauth2/code/kakao

(2) 카카오로 933037 디벨로퍼스앱의 액세스 토큰 발급 요청 로그가 없습니다.

  • 앱키를 잘못사용했거나 형식에 맞지않아 933037 디벨로퍼스앱의 에러로그가 아닌 불특정 에러로그로 남았을 수도 있습니다.

리다이렉트 URI에서 토큰 발급요청 응답확인 부탁드려요.

현재 로그로 에러 다시 확인해보았는데 invalid_request 에러가 발생해서 액세스 토큰 발급 요청을 하지 못 하는 것 같습니다.
이런 경우에는 어떻게 해결해야할까요?

application.yml이나 프로퍼티 파일 oauth2 설정부 공유해주시겠어요?

spring:
  security:
    oauth2:
      client:
        registration:
          kakao:
            client-id: 91cfc73a730663e93196247d884f837e
            redirect-uri: https://takgyun.shop/login/oauth2/code/kakao
            authorization-grant-type: authorization_code
            client-authentication-method: POST
            client-name: Kakao
            scope:
              - profile_nickname
              - account_email
        provider:
          kakao:
            authorization-uri: https://kauth.kakao.com/oauth/authorize
            token-uri: https://kauth.kakao.com/oauth/token
            user-info-uri: https://kapi.kakao.com/v2/user/me
            user-name-attribute: id

배포 환경에서의 application-oauth.yml 입니다!

redirect-uri: /login/oauth2/code/kakao

리다이렉트 URI를 실행중인 서버가 아니라 다른곳으로 지정해서 에러 발생한것같네요. 위와 같이 처리 부탁드려요.