Google 소셜 로그인에 이어 Kakao 소셜 로그인을 구현하려고 한다.
Kakao 소셜 로그인은 Google 때 구현해놓았던 틀을 기반으로 아주 간단하게 추가하므로 기반 코드가 없다면 아래 포스팅을 참고하면 좋겠다.
[SpringBoot] Google 소셜 로그인 구현: OAuth2.0 & Spring Security 활용
코드 구현에 앞서, 소셜 로그인 개념은 아래 포스팅을 참고하면 좋겠다. Spring Security & OAuth2.0 & JWT Token 소셜로그인 개념 정리Spring Security 란?Spring Security는 애플리케이션의 보안을 담당하는 프레
seung-yo.tistory.com
폴더 구조
Kakao 소셜 로그인은 이전 포스팅을 따라 틀을 갖춰 놓았다면 따로 추가할 필요가 없다. 이번 시간에는 KakaoOauth.java, application.properties 파일만 수정할 예정이다.
소셜 로그인 요청 Redirect 처리 (Kakao)
- KakaoOauth 클래스 수정
Google 로그인 때와 비슷하게 사용자가 카카오 인증을 요청할 수 있는 URL을 생성하고, 받은 인증 코드를 이용해 액세스 토큰을 요청하는 기능을 제공하는 코드이다. RestTemplate과 HttpURLConnection 두 가지 방법으로 액세스 토큰을 요청할 수 있으며, 성공적으로 토큰을 받으면 이를 콘솔에 출력하는 코드를 추가했다.
KakaoOauth.java
package com.example.Profee.service.social;
import lombok.RequiredArgsConstructor;
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;
// 공통 interface를 구현할 소셜 로그인 각 타입별 Class 생성 (Kakao)
@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.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("grant_type", "authorization_code");
params.put("client_id", KAKAO_SNS_CLIENT_ID);
params.put("redirect_uri", KAKAO_SNS_CALLBACK_URL);
params.put("code", code);
ResponseEntity<String> responseEntity =
restTemplate.postForEntity(KAKAO_SNS_TOKEN_BASE_URL, params, String.class);
if (responseEntity.getStatusCode() == HttpStatus.OK) {
// 콘솔에 받은 토큰 출력
String tokenResponse = responseEntity.getBody();
System.out.println("Received Access Token: " + tokenResponse);
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("grant_type", "authorization_code");
params.put("client_id", KAKAO_SNS_CLIENT_ID);
params.put("redirect_uri", KAKAO_SNS_CALLBACK_URL);
params.put("code", 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) {
// 콘솔에 받은 토큰 출력
String tokenResponse = sb.toString();
System.out.println("Received Access Token: " + tokenResponse);
return tokenResponse;
}
return "카카오 로그인 요청 처리 실패";
} catch (IOException e) {
throw new IllegalArgumentException("알 수 없는 카카오 로그인 Access Token 요청 URL 입니다 :: " + KAKAO_SNS_TOKEN_BASE_URL);
}
}
}
카카오 소셜 로그인에서 액세스 토큰을 요청하는 두 가지 방법이 있는데, 바로 Spring의 RestTemplate과 자바 기본 API인 HttpURLConnection을 사용하는 방법이다. 이 두 방법의 주요 차이점은 사용의 편의성과 코드 복잡성에 있다. 물론 두 방법을 모두 구현할 필요는 없지만 공부 차원에서 메서드를 남겨두었다. (Google 소셜 로그인도 동일하게 남겨두었다.)
1. RestTemplate 방식 (requestAccessToken)
- Spring 프레임워크의 고수준 HTTP 클라이언트: RestTemplate은 Spring에서 제공하는 HTTP 통신을 위한 유틸리티 클래스로, REST API 호출을 간단하게 처리할 수 있도록 설계되었다.
- 장점:
- 코드가 간결하고 읽기 쉬움.
- 다양한 HTTP 메서드(GET, POST, PUT, DELETE 등)를 간편하게 사용할 수 있음.
- 예외 처리 및 응답 매핑이 내장되어 있어 개발자가 수동으로 처리할 필요가 없음.
- Spring 프로젝트에서는 RestTemplate을 사용하면 일관된 코드 스타일을 유지할 수 있음.
- 단점:
- Spring에 의존적이기 때문에, Spring 프레임워크가 필요 없는 상황에서는 사용이 부적절할 수 있음.
2. HttpURLConnection 방식 (requestAccessTokenUsingURL)
- 자바 기본 API: HttpURLConnection은 자바 표준 API로, 네트워크 통신을 저수준에서 직접 제어할 수 있는 클래스를 제공한다.
- 장점:
- 자바 표준 API만으로 동작하므로, 외부 라이브러리에 의존하지 않음.
- 네트워크 요청에 대한 세부 제어가 가능하므로, 매우 세밀한 설정이나 통신 요구가 있을 때 적합함.
- 단점:
- 코드가 복잡하고 장황함.
- 예외 처리, 응답 매핑 등을 수동으로 해야 하므로 실수할 가능성이 있음.
- 유지보수가 어렵고, 코드 가독성이 떨어짐.
RestTemplate VS. HttpURLConnection
- RestTemplate: 코드가 간결하고, Spring 애플리케이션에서 쉽게 통합할 수 있는 방식으로, 유지보수 및 가독성 면에서 유리하다. Spring 기반 프로젝트에서는 주로 이 방식을 권장한다.
- HttpURLConnection: 더 저수준에서 네트워크 통신을 제어할 수 있지만, 코드가 복잡해지고 실수할 가능성이 크며 유지보수가 어렵다. 특별한 이유가 없다면 이 방식은 피하는 것이 좋다.
따라서, 두 가지 방법을 모두 사용할 필요는 없으며 RestTemplate만 사용하는 것이 더 효율적이다.
application.properties 파일 설정
Google 때와 동일하게 Kakao를 통해 발급받은 클라이언트 아이디(= Rest API 키)와 시크릿을 입력해주면 된다. 편의상 Google과 Kakao를 구분하는 주석을 추가했다.
application.properties
# Google
sns.google.url=https://accounts.google.com/o/oauth2/v2/auth
sns.google.client.id=구글 클라이언트 아이디
sns.google.client.secret=구글 클라이언트 시크릿
sns.google.callback.url=http://localhost:8080/auth/google/callback
sns.google.token.url=https://oauth2.googleapis.com/token
# Kakao
sns.kakao.url=https://kauth.kakao.com/oauth/authorize
sns.kakao.client.id=카카오 클라이언트 아이디
sns.kakao.client.secret=카카오 클라이언트 시크릿
sns.kakao.callback.url=http://localhost:8080/auth/kakao/callback
sns.kakao.token.url=https://kauth.kakao.com/oauth/token
이후 Spring Boot 서버를 구동시킨 다음 http://localhost:8080/auth/kakao 로 들어가면 다음과 같이 카카오 소셜 로그인이 잘 되는것을 확인할 수 있다. 😄
'프로젝트 > Profee' 카테고리의 다른 글
[RN] 안드로이드 에뮬레이터 까만 화면만 나올 때 (0) | 2024.10.14 |
---|---|
[SpringBoot] Naver 소셜 로그인 구현: OAuth2.0 & Spring Security 활용 (0) | 2024.09.11 |
[SpringBoot] 400 오류: redirect_uri_mismatch 오류 해결 (0) | 2024.09.10 |
[SpringBoot] Google 소셜 로그인 구현: OAuth2.0 & Spring Security 활용 (0) | 2024.09.10 |
[RN] React Native 프로젝트 Xcode 오류 해결: Could Not Open File (0) | 2024.09.07 |