원래 자체 서비스에서도 OAuth2를 사용하려고 했는데 Spring Security를 사용하지 말라는 공지가 들어왔다. 아쉽지만 OAuth2를 사용하지 않고 서비스에 소셜 로그인을 적용하기로 했다. (어차피 카카오 소셜 로그인 API는 OAuth2 기반이라 괜찮을 지도 모른다는 생각도 ...ㅎ-ㅎ)
카카오 소셜 로그인을 자바에 적용시키는 방법은 크게 아래와 같은 차례를 따른다.
1. Kakao Developer에서 클라이언트 키 발급받기
2. 키를 사용해 API에 인가 코드 요청 보내기
3. 받은 인가 코드를 사용해 API에 토큰 발급 요청 보내기
4. 받은 토큰을 활용해 사용자 정보 가져오기
5. 로그아웃 하기
리팩토링을 거치지 않은 코드다... 🙃 흐름을 이해한다는 데 의의를 두자ㅎㅎ
(+) 2020.07.17. RestTemplate 대신 WebClinet 적용 코드로 수정
1. Kakao Developer에서 클라이언트 키 발급받기
Kakao Developer 에 접속하여 로그인 한 후 상단에 있는 '내 어플리케이션' 을 클릭한다.
애플리케이션 추가하기를 누르고 필요한 정를 입력한다.
생성한 앱을 클릭하면 좌측의 '앱 설정 - 요약 정보' 란에서 앱 키를 확인할 수 있다. 여기서 우리가 사용할 키는 REST API 키이다.
이후 좌측의 '제품 설정 - 카카오 로그인' 란에서 카카오 로그인을 활성화 한다. Redirect URL도 설정해놓는다.
2. 키를 사용해 API에 인가 코드 요청 보내기
본론에 들어가기에 앞서 카카오 로그인이 진행되는 절차는 다음과 같다.
1) 클라이언트 측에서 어플리케이션에 로그인 요청을 보내면
2) 어플리케이션 서버에서 카카오 서버에 인증 코드 요청을 보낸다. (카카오 서버에선 어플리케이션 서버가 클라이언트와 같은 셈)
3) 카카오 서버에서 인가 코드를 발급해 redirect_url 에 전달하면 (=클라이언트가 어플리케이션에 다시 요청을 보냄)
4) 어플리케이션 서버에서 받은 인가 코드를 활용해 카카오 서버에 토큰을 요청한다.
5) 토큰을 받으면 필요한 API를 호출한다. (나의 경우 '사용자 정보 가져오기'를 사용했다.)
우리 팀의 경우 요청 API를
- 인가 코드 받기 : /kakao/oauth
- 리다이렉트 URL : /kakao/callback
- 로그아웃 : /kakao/logout
로 하였다. 각자 프로젝트의 명세서에 따라 이 부분은 달라질 수 있음을 유의해두자.
인가 코드 받기 Request 파라미터를 참고해 요청을 보낸다.
@Controller
@RequestMapping("/api/kakao")
public class KakaoController {
public KakaoController() {
}
@GetMapping(value = "/oauth")
public String kakaoConnect() {
StringBuffer url = new StringBuffer();
url.append("https://kauth.kakao.com/oauth/authorize?");
url.append("client_id=" + 발급받은 REST API 키);
url.append("&redirect_uri=http://localhost:8080/kakao/callback");
url.append("&response_type=code");
return "redirect:" + url;
}
// ...하략
}
3. 받은 인가 코드를 사용해 API에 토큰 발급 요청 보내기
토큰 받기 Request 파라미터를 참고해 요청을 보낸다.
@RequestMapping(value = "/callback", produces = "application/json", method = {RequestMethod.GET,
RequestMethod.POST})
public void kakaoLogin(@RequestParam("code") String code,
HttpSession session) throws IOException {
String accessToken = getKakaoAccessToken(code);
session.setAttribute("access_token", accessToken); // 로그아웃할 때 사용된다
}
public String getKakaoAccessToken(String code) {
// 카카오에 보낼 api
WebClient webClient = WebClient.builder()
.baseUrl("https://kauth.kakao.com")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
// 카카오 서버에 요청 보내기 & 응답 받기
JSONObject response = webClient.post()
.uri(uriBuilder -> uriBuilder
.path("/oauth/token")
.queryParam("grant_type", "authorization_code")
.queryParam("client_id", SecretKey.KAKAO_API_KEY)
.queryParam("redirect_uri", Kakao.DOMAIN_URI + "/api/kakao/callback")
.queryParam("code", code)
.build())
.retrieve().bodyToMono(JSONObject.class).block();
return (String) response.get("access_token");
}
4. 받은 토큰을 활용해 사용자 정보 가져오기
내 애플리케이션 - '제품 설정 - 동의 항목' 란에서 카카오 로그인으로 서비스를 시작할 때 동의 받는 항목을 설정한다.
필수, 선택, 사용하지 않음 중에 고를 수 있는데 일부 정보는 필수로 하기 위해선 절차를 좀 더 밟아야 한다.
여기선 별다를 절차 없이 필수가 가능한 항목 중 닉네임, 프로필 사진을 가져오기로 했다.
받을 항목 지정이 끝났으면 사용자 정보 가져오기 Request 파라미터를 참고해 요청을 보낸다.
@RequestMapping(value = "/callback", produces = "application/json",
method = {RequestMethod.GET, RequestMethod.POST})
public void kakaoLogin(@RequestParam("code") String code, HttpSession session)
throws IOException {
// ...생략
getKakaoUserInfo(accessToken);
}
private void getKakaoUserInfo(String accessToken) {
// 카카오에 요청 보내기 및 응답 받기
WebClient webClient = WebClient.builder()
.baseUrl("https://kapi.kakao.com")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
JSONObject response = webClient.post()
.uri(uriBuilder -> uriBuilder.path("/v2/user/me").build())
.header("Authorization", "Bearer " + access_token)
.retrieve().bodyToMono(JSONObject.class).block();
// 받은 응답에서 원하는 정보 추출하기 (여기의 경우 회원 고유번호와 카카오 닉네임)
Integer id = (Integer) response.get("id");
Map<String, Object> map = (Map<String, Object>)
response.get("kakao_account");
Map<String, Object> profile = (Map<String, Object>) map.get("profile");
String name = (String) profile.get("nickname");
// 추출한 정보로 원하는 처리를 함
}
여기서 얻은 사용자 정보를 활용해 서비스를 제공할 수 있다. 이것 외에도 다양한 API를 사용할 수 있으니 문서를 잘 활용해보자.
5. 로그아웃하기
로그아웃하기 Request 파라미터를 참고해 요청을 보낸다.
@GetMapping(value = "/logout")
public String kakaoLogout(HttpSession session) {
String accessToken = (String) session.getAttribute("access_token);
// 카카오에 요청 보내기
WebClient webClient = WebClient.builder()
.baseUrl("https://kapi.kakao.com")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
JSONObject response = webClient.post()
.uri(uriBuilder -> uriBuilder.path("/v1/user/logout").build())
.header("Authorization", "Bearer " + accessToken)
.retrieve().bodyToMono(JSONObject.class).block();
// 로그아웃하면서 만료된 토큰을 세션에서 삭제
session.removeAttribute("access_token");
return "redirect:" + 초기화면 링크
}
6. 참고 자료
- 스프링부트 카카오 로그인하기 구현(따라치기만하면됨)
- Spring MVC 카카오 아이디로 로그인(REST API)
7. 사담
OAuth2를 직접 사용해보고 싶었는데 못해서 아쉽다. 시간 날 때 OAuth2 실습도 해볼 예정이다.
'자바 뚝딱거리기' 카테고리의 다른 글
[JAVA] 커스텀 어노테이션 만들기.. 그런데 Path Variable를 곁들인 (0) | 2022.11.22 |
---|---|
[JAVA] 네이버 소셜 로그인 REST API 적용하기 (0) | 2021.07.17 |
[JPA] 3. 영속성 관리 (0) | 2021.07.09 |
[JPA] InteliJ + gradle + SpringBoot + h2 DB(or MySQL) 로 간단 CRUD 기능 구현하기 (2.JPA 시작) (0) | 2021.06.24 |
[JPA] JPA는 왜 써야할까? (1. JPA 소개) (0) | 2021.06.24 |