문제 분석
- 인가 코드 전달:
- 로그에 따르면 카카오에서 인가 코드를 정상적으로 전달했습니다: /oauth2/callback/kakao?code=ZOpZTERTp_LLVONEERC39081grIdTJz2WVvV_v6Dq9oTCHlk81-3ogAAAAQKKiWRAAABj_fQWcMq17LwdM8QAg.
- 에러 발생:
- 이후 /oauth2/login/kakao?error로 리디렉션되었습니다. 이는 인가 코드 처리 과정에서 문제가 발생했음을 의미합니다.
해결 방법
- 로그 확인:
- 먼저, 로그에서 더 많은 정보를 확인합니다. 특히, DEBUG 레벨의 로그를 통해 어떤 에러가 발생했는지 확인합니다. Stacktrace를 통해 에러의 원인을 파악할 수 있습니다.
- OAuth2 설정 확인:
- 스프링 시큐리티 설정 파일에서 카카오 OAuth2 설정이 올바른지 확인합니다. 예를 들어, application.yml 또는 application.properties 파일에서 클라이언트 ID, 클라이언트 시크릿, 리디렉션 URI 등이 올바르게 설정되었는지 확인합니다.
yaml
spring:
security:
oauth2:
client:
registration:
kakao:
client-id: <your-client-id>
client-secret: <your-client-secret>
redirect-uri: "{baseUrl}/oauth2/callback/kakao"
authorization-grant-type: authorization_code
scope: profile
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
- 콜백 URL 확인:
- 카카오 개발자 센터에서 설정한 리디렉션 URI가 애플리케이션의 리디렉션 URI와 일치하는지 확인합니다. 리디렉션 URI가 일치하지 않으면 인가 코드 처리에 실패할 수 있습니다.
- 스프링 시큐리티 설정 확인:
- 스프링 시큐리티 설정 클래스에서 OAuth2 로그인 설정이 올바른지 확인합니다. 예를 들어, OAuth2LoginConfigurer가 제대로 설정되었는지 확인합니다.
java
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home", "/login**", "/error**").permitAll()
.anyRequest().authenticated()
.and()
.oauth2Login()
.defaultSuccessUrl("/loginSuccess")
.failureUrl("/loginFailure")
.userInfoEndpoint()
.userService(customOAuth2UserService); // 사용자 정보를 처리하는 서비스
}
}
- 카카오 API 호출 확인:
- 인가 코드를 사용하여 카카오에서 액세스 토큰을 받는 과정에서 문제가 발생했을 수 있습니다. 이를 확인하기 위해 API 호출 및 응답을 확인합니다.
java
public OAuth2AccessToken getAccessToken(String code) {
OAuth2AccessTokenResponse response = restTemplate.postForObject(
"https://kauth.kakao.com/oauth/token",
new HttpEntity<>(getAccessTokenRequest(code), getHttpHeaders()),
OAuth2AccessTokenResponse.class
);
return response.getAccessToken();
}
결론
위의 단계들을 차례로 확인하고 설정을 수정하면, 카카오 로그인 과정에서 발생하는 문제를 해결할 수 있을 것입니다. 각 단계에서 발생하는 로그와 에러 메시지를 주의 깊게 확인하는 것이 중요합니다. 필요하다면 추가적인 디버깅 정보를 제공해 주시면 더 구체적인 도움을 드릴 수 있습니다.
UserService, UserRepository, OAuth2LoginSuccessHandler, OAuth2UserService
if (existedUser) {
val user = userService.findUser(
OAuth2Provider.valueOf(userInfo.provider),
userInfo.providerId,
)
val accessToken = jwtHelper.generateAccessToken(
user.providerId, user.nickname, httpServletResponse
)
httpServletResponse.addHeader("Authorization", "Bearer $accessToken")
httpServletResponse.contentType = MediaType.APPLICATION_JSON_VALUE
httpServletResponse.sendRedirect("/")
}
수정된 코드
if (existedUser) {
val user = userService.findUser(
OAuth2Provider.valueOf(userInfo.provider),
userInfo.providerId,
)
if (user != null) { // 추가된 null 체크
val accessToken = jwtHelper.generateAccessToken(
user.providerId, user.nickname, httpServletResponse
)
httpServletResponse.addHeader("Authorization", "Bearer $accessToken")
httpServletResponse.contentType = MediaType.APPLICATION_JSON_VALUE
httpServletResponse.sendRedirect("/")
} else {
// user가 null인 경우에 대한 처리
httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "User not found")
}
}
이렇게 해봐도 안된다..
- OAuth2 설정 확인:
- Kakao Developers 콘솔에서 설정된 리다이렉트 URI가 애플리케이션의 리다이렉트 URI와 일치하는지 확인하세요.
- 클라이언트 ID와 시크릿이 올바르게 설정되어 있는지 확인하세요.
- 로그인 엔드포인트 확인:
- /oauth2/callback/kakao 경로가 올바르게 설정되어 있는지 확인하세요.
- 애플리케이션에서 OAuth2 설정을 담당하는 부분을 확인하고, 잘못된 설정이 없는지 검토하세요.
- 오류 로그 추가:
- 현재 로그에는 구체적인 오류 원인이 나와있지 않으므로, 오류 발생 시 구체적인 예외 메시지를 로그에 남기도록 설정하세요. 이를 통해 어떤 부분에서 문제가 발생하는지 더 명확히 알 수 있습니다.
- 디버깅:
- 디버깅 모드로 애플리케이션을 실행하여, OAuth2 인증 과정에서 어떤 값들이 반환되는지 확인하세요.
- 특히, Authorization Code가 올바르게 전달되고 있는지 확인하세요.
- Spring Security 설정 확인:
- SecurityConfig 클래스에서 OAuth2 설정이 올바르게 되어 있는지 확인하세요.
- 필요한 경우, 추가적인 설정이나 필터를 통해 문제를 해결할 수 있습니다.
다음은 Spring Security 설정 예시입니다:
java
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/oauth2/**", "/login/**").permitAll()
.anyRequest().authenticated()
.and()
.oauth2Login()
.loginPage("/login")
.defaultSuccessURL("/home")
.failureURL("/login?error")
.userInfoEndpoint()
.userService(oAuth2UserService);
}
}
이렇다는데 과연???