구글 소셜 로그인을 구현했던 이전글에 이어서 카카오 소셜 로그인을 구현해보도록 하겠습니다.
구글 소셜 로그인 구현 방법은 아래 글에서 확인할 수 있습니다
⭐ 코드 설명
✅ Service 폴더 - Social 폴더
☑️ KakaoOauth.java 파일
package com.example.CocO.service.social;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j
@Component
@RequiredArgsConstructor
public class KakaoOauth implements SocialOauth {
@Value("${sns.kakao.url}")
private String KAKAO_SNS_BASE_URL;
@Value("${sns.kakao.client.id}")
private String KAKAO_SNS_CLIENT_ID;
@Value("${sns.kakao.callback.url}")
private String KAKAO_SNS_CALLBACK_URL;
@Value("${sns.kakao.client.secret}")
private String KAKAO_SNS_CLIENT_SECRET;
@Value("${sns.kakao.token.url}")
private String KAKAO_SNS_TOKEN_BASE_URL;
@Override
public String getOauthRedirectURL() {
Map<String, Object> params = new HashMap<>();
params.put("response_type", "code");
params.put("client_id", KAKAO_SNS_CLIENT_ID);
params.put("redirect_uri", KAKAO_SNS_CALLBACK_URL);
String parameterString = params.entrySet().stream()
.map(x -> x.getKey() + "=" + x.getValue())
.collect(Collectors.joining("&"));
return KAKAO_SNS_BASE_URL + "?" + parameterString;
}
@Override
public String requestAccessToken(String code) {
RestTemplate restTemplate = new RestTemplate();
Map<String, Object> params = new HashMap<>();
params.put("code", code);
params.put("client_id", KAKAO_SNS_CLIENT_ID);
params.put("client_secret", KAKAO_SNS_CLIENT_SECRET);
params.put("redirect_uri", KAKAO_SNS_CALLBACK_URL);
params.put("grant_type", "authorization_code");
ResponseEntity<String> responseEntity =
restTemplate.postForEntity(KAKAO_SNS_TOKEN_BASE_URL, params, String.class);
if (responseEntity.getStatusCode() == HttpStatus.OK) {
return responseEntity.getBody();
}
return "카카오 로그인 요청 처리 실패";
}
public String requestAccessTokenUsingURL(String code) {
try {
URL url = new URL(KAKAO_SNS_TOKEN_BASE_URL);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setDoOutput(true);
Map<String, Object> params = new HashMap<>();
params.put("code", code);
params.put("client_id", KAKAO_SNS_CLIENT_ID);
params.put("client_secret", KAKAO_SNS_CLIENT_SECRET);
params.put("redirect_uri", KAKAO_SNS_CALLBACK_URL);
params.put("grant_type", "authorization_code");
String parameterString = params.entrySet().stream()
.map(x -> x.getKey() + "=" + x.getValue())
.collect(Collectors.joining("&"));
BufferedOutputStream bous = new BufferedOutputStream(conn.getOutputStream());
bous.write(parameterString.getBytes());
bous.flush();
bous.close();
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
if (conn.getResponseCode() == 200) {
return sb.toString();
}
return "카카오 로그인 요청 처리 실패";
} catch (IOException e) {
throw new IllegalArgumentException("알 수 없는 카카오 로그인 Access Token 요청 URL 입니다 :: " + KAKAO_SNS_TOKEN_BASE_URL);
}
}
}
OAuth 리다이렉트 URL 생성
getOauthRedirectURL() 메서드
- 이 메서드는 사용자가 카카오 로그인 버튼을 눌렀을 때, 카카오 로그인 페이지로 리다이렉트하기 위한 URL을 생성합니다.
- 카카오 인증 서버로 요청을 보내기 위한 파라미터들을 Map에 담은 후, 이를 key=value 형식으로 변환해 URL에 붙여 리턴합니다.
- 파라미터로는 response_type(고정값 "code"), client_id, redirect_uri를 사용하며, 이는 카카오 OAuth에서 인증 코드를 받기 위한 기본적인 정보입니다.
액세스 토큰 요청
카카오 인증을 완료한 후, 받은 인증 코드를 바탕으로 액세스 토큰을 요청하는 두 가지 방법이 구현되어 있습니다.
A. RestTemplate을 사용한 방식
requestAccessToken(String code) 메서드
- 스프링의 RestTemplate을 이용하여 HTTP POST 요청을 보내고, 액세스 토큰을 요청하는 메서드입니다.
- 인증 서버로 보낼 파라미터들을 Map으로 구성한 후, RestTemplate의 postForEntity 메서드를 사용하여 토큰 요청을 처리합니다.
- 요청이 성공하면 응답의 HTTP 상태 코드를 확인한 후, 성공적인 경우 응답 본문에 포함된 데이터를 반환합니다. 실패하면 "카카오 로그인 요청 처리 실패" 메시지를 반환합니다.
B. HttpURLConnection을 사용한 방식
requestAccessTokenUsingURL(String code) 메서드
- HttpURLConnection을 직접 사용하여 카카오 서버에 POST 요청을 보내고, 액세스 토큰을 요청하는 메서드입니다.
- URL 객체를 생성하고, 연결을 설정한 후, 파라미터를 전송합니다. 이후 응답 스트림을 읽어 결과를 처리합니다.
- 응답 코드가 200일 경우 정상적으로 토큰 정보를 반환하고, 그렇지 않으면 "카카오 로그인 요청 처리 실패" 메시지를 반환합니다.
- 이 방식은 RestTemplate보다 더 저수준의 HTTP 요청 처리를 직접 다루는 방식으로, HTTP 연결을 수동으로 설정하고, 출력 스트림과 입력 스트림을 사용해 데이터를 전송 및 수신합니다.
✅ resources - application.properties 파일
sns.kakao.url=https://kauth.kakao.com/oauth/authorize
sns.kakao.client.id=<카카오 개발자 센터에서 발급받은 REST API Key>
sns.kakao.client.secret=<카카오 개발자 센터에서 발급받은 클라이언트 Secret>
sns.kakao.callback.url=http://localhost:8080/auth/kakao/callback
sns.kakao.token.url=https://kauth.kakao.com/oauth/token
⭐ 테스트
이제 Spring Boot 서버를 구동한 후, 카카오소셜 로그인을 테스트할 수 있습니다.
먼저, Spring Boot 서버를 실행합니다. 저는 현재 로컬에서 개발 중이어서 localhost:8080로 실행되고 있습니다.
크롬과 같은 웹 브라우저를 사용해서 테스트 한다면 아래 링크에서 확인할 수 있습니다.
http://localhost:8080/auth/kakao
혹은 Postman과 같은 API 도구를 사용한다면 아래와 같이 요청을 보냅니다.
GET http://localhost:8080/auth/kakao
요청을 보내면 콘솔 로그에서 다음과 같은 결과를 확인할 수 있습니다.
📌 참고