-
[Kakao Login] 카카오 로그인 구현하기 (초기세팅 / 값 받아오기)Spring Boot 2024. 1. 18. 15:48
소셜 로그인 초기 세팅
참고사이트 :
[개인프로젝트] 소셜로그인 기능 추가 (구글, 카카오, 네이버/ Rest API, Spring Boot)
[개인프로젝트] 소셜로그인 기능 추가 (구글, 카카오, 네이버/ Rest API, Spring Boot)
목차 1. 각각의 소셜 플랫폼에서 환경구성하기 2. 소셜로그인 Rest API 구현하기 1) 로그인 최초 요청 처리 (code 받기) 2) 로그인 이후 요청 처리 (받은 code로 token 받기) 3) 클라이언트에 반환하기 (받
yeees.tistory.com
- 참고한 링크는 최상단에 표시함.
- 링크로 들어가서 로그인 후 회원 가입하기 (Kakao Developers)
- 플랫폼 - Web 플랫폼 등록
- 앱 권한 신청하기
- 보안 - client 시크릿 키 지정
- Redirect URL은 http://localhost:8080
- 활성화 설정 꼭 해주기
- 401에러 해결법 (java.io.IOException: Server returned HTTP response code: 401 for URL: https://kauth.kakao.com/oauth/token)
- 고급 설정 - 허용 IP 설정 - 본인의 ip 주소를 넣어주어야 함.
- client secret은 설정할거면 파라미터 값으로 넘겨주어야 함.
- sb.append("&cliend_secret=--------------");
LoginController
package com.se.social.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import com.se.social.service.KakaoAPI; import lombok.AllArgsConstructor; import lombok.extern.log4j.Log4j2; @Log4j2 @AllArgsConstructor @RequestMapping(value = "/social") @Controller public class LoginController { private KakaoAPI kakao; @GetMapping("loginpage") public void getLogin() { } @RequestMapping(value="/login") public String login(@RequestParam("code") String code) { String access_Token = kakao.getAccessToken(code); System.out.println("controller access_token : " + access_Token); System.out.println("code : " + code); return "home"; } }
KakaoAPIService
package com.cm.personalProject.service; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; import java.net.URL; import java.util.HashMap; import org.springframework.stereotype.Service; import com.cm.personalProject.entity.User; import com.cm.personalProject.repository.UserRepository; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; @Service @RequiredArgsConstructor @Log4j2 public class KakaoAPI { private final UserRepository repository; public String getAccessToken(String authorize_code) { String access_Token = ""; String refresh_Token = ""; String reqURL = "https://kauth.kakao.com/oauth/token"; try { URL url = new URL(reqURL); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); // POST 요청을 위해 기본값이 false인 setDoOutput을 true로 conn.setRequestMethod("POST"); conn.setDoOutput(true); // POST 요청에 필요로 요구하는 파라미터 스트림을 통해 전송 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream())); StringBuilder sb = new StringBuilder(); sb.append("grant_type=authorization_code"); sb.append("&client_id=-----------"); sb.append("&redirect_uri=http://localhost:8080/social/login"); sb.append("&code=" + authorize_code); sb.append("&client_secret=------------------"); bw.write(sb.toString()); bw.flush(); // 결과 코드가 200이라면 성공 int responseCode = conn.getResponseCode(); System.out.println("responseCode : " + responseCode); // 요청을 통해 얻은 JSON타입의 Response 메세지 읽어오기 BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); String line = ""; String result = ""; while ((line = br.readLine()) != null) { result += line; } System.out.println("response body : " + result); // Gson 라이브러리에 포함된 클래스로 JSON파싱 객체 생성 JsonParser parser = new JsonParser(); JsonElement element = parser.parse(result); access_Token = element.getAsJsonObject().get("access_token").getAsString(); refresh_Token = element.getAsJsonObject().get("refresh_token").getAsString(); System.out.println("access_token : " + access_Token); System.out.println("refresh_token : " + refresh_Token); br.close(); bw.close(); } catch (IOException e) { e.printStackTrace(); } return access_Token; } // getAccessToken() // getUserInfo public HashMap<String, Object> getUserInfo(String access_token) { // 요청하는 클라이언트마다 가진 정보가 다를 수 있기에 HashMap 타입으로 선 HashMap<String, Object> userInfo = new HashMap<>(); String reqUrl = "https://kapi.kakao.com/v2/user/me"; try { URL url = new URL(reqUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); // 요청에 필요한 Header에 포함될 내용 conn.setRequestProperty("Authorization", "Bearer " + access_token); // conn.setRequestProperty("Content-type", // "application/x-www-form-urlencoded;charset=utf-8"); int responseCode = conn.getResponseCode(); log.info("[KakaoApi.getUserInfo] responseCode : {}", responseCode); BufferedReader br; if (responseCode >= 200 && responseCode <= 300) { br = new BufferedReader(new InputStreamReader(conn.getInputStream())); } else { br = new BufferedReader(new InputStreamReader(conn.getErrorStream())); } String line = ""; StringBuilder responseSb = new StringBuilder(); while ((line = br.readLine()) != null) { responseSb.append(line); } String result = responseSb.toString(); log.info("responseBody = {}", result); JsonParser parser = new JsonParser(); JsonElement element = parser.parse(result); JsonObject properties = element.getAsJsonObject().get("properties").getAsJsonObject(); JsonObject kakao_account = element.getAsJsonObject().get("kakao_account").getAsJsonObject(); String nickname = properties.getAsJsonObject().get("nickname").getAsString(); String profile_image = properties.getAsJsonObject().get("profile_image").getAsString(); String email = kakao_account.getAsJsonObject().get("email").getAsString(); userInfo.put("nickname", nickname); userInfo.put("email", email); userInfo.put("profile_image", profile_image); User user = new User(); user.setUseremail(email); user.setUsername(nickname); user.setOauthtype("kakao"); user.setOauthtoken("00000"); user.setUserphone("01000000000"); user.setUserbirthday("19000000"); System.out.println("user!!!!!!!" + user); repository.save(user); br.close(); } catch (Exception e) { e.printStackTrace(); } return userInfo; } }
loginPage.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <a href="https://kauth.kakao.com/oauth/authorize?client_id=7c340b218caf1b7c5c6faed3222c37d3&redirect_uri=http://localhost:8080/social/login&response_type=code"> <img src="/resources/images/kakao_login_medium_wide.png" alt="kakaoLogin IMG" /> </a> <a>google 로그인</a> <a>kakao 로그인</a> </body> </html>
- 처음에는 a태그 링크가 너무 길어서 enter를 했는데 그러면 공백이 생겨서 제대로 된 정보가 넘어가지 않음.
- service에서 @Autowired 대신 @RequiredArgsConstructor을 사용하기를 권장함
- 단일 책임 원칙 관점
- field에 final 키워드 사용
- 순환 참조 방지
- 결합도 낮춰 테스트 용이
- 하지만 우리가 service에서 UserRepository repository;로 불러오니 @RequiredArgsConstructor을 사용해도 nullpointerException이 발생하였다. 그 이유는 다음과 같다.
KakaoAPIService
package com.cm.personalProject.service; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; import java.net.URL; import java.util.HashMap; import org.springframework.stereotype.Service; import com.cm.personalProject.entity.User; import com.cm.personalProject.repository.UserRepository; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; @Service @RequiredArgsConstructor @Log4j2 public class KakaoAPI { private final UserRepository repository; public String getAccessToken(String authorize_code) { String access_Token = ""; String refresh_Token = ""; String reqURL = "https://kauth.kakao.com/oauth/token"; try { URL url = new URL(reqURL); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); // POST 요청을 위해 기본값이 false인 setDoOutput을 true로 conn.setRequestMethod("POST"); conn.setDoOutput(true); // POST 요청에 필요로 요구하는 파라미터 스트림을 통해 전송 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream())); StringBuilder sb = new StringBuilder(); sb.append("grant_type=authorization_code"); sb.append("&client_id=7c340b218caf1b7c5c6faed3222c37d3"); sb.append("&redirect_uri=http://localhost:8080/social/login"); sb.append("&code=" + authorize_code); sb.append("&client_secret=MP2DGb1FU2Xa3QcDKodnB1zTzEQLzGn5"); bw.write(sb.toString()); bw.flush(); // 결과 코드가 200이라면 성공 int responseCode = conn.getResponseCode(); System.out.println("responseCode : " + responseCode); // 요청을 통해 얻은 JSON타입의 Response 메세지 읽어오기 BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); String line = ""; String result = ""; while ((line = br.readLine()) != null) { result += line; } System.out.println("response body : " + result); // Gson 라이브러리에 포함된 클래스로 JSON파싱 객체 생성 JsonParser parser = new JsonParser(); JsonElement element = parser.parse(result); access_Token = element.getAsJsonObject().get("access_token").getAsString(); refresh_Token = element.getAsJsonObject().get("refresh_token").getAsString(); System.out.println("access_token : " + access_Token); System.out.println("refresh_token : " + refresh_Token); br.close(); bw.close(); } catch (IOException e) { e.printStackTrace(); } return access_Token; } // getAccessToken() // getUserInfo public HashMap<String, Object> getUserInfo(String access_token) { // 요청하는 클라이언트마다 가진 정보가 다를 수 있기에 HashMap 타입으로 선 HashMap<String, Object> userInfo = new HashMap<>(); String reqUrl = "https://kapi.kakao.com/v2/user/me"; try { URL url = new URL(reqUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); // 요청에 필요한 Header에 포함될 내용 conn.setRequestProperty("Authorization", "Bearer " + access_token); // conn.setRequestProperty("Content-type", // "application/x-www-form-urlencoded;charset=utf-8"); int responseCode = conn.getResponseCode(); log.info("[KakaoApi.getUserInfo] responseCode : {}", responseCode); BufferedReader br; if (responseCode >= 200 && responseCode <= 300) { br = new BufferedReader(new InputStreamReader(conn.getInputStream())); } else { br = new BufferedReader(new InputStreamReader(conn.getErrorStream())); } String line = ""; StringBuilder responseSb = new StringBuilder(); while ((line = br.readLine()) != null) { responseSb.append(line); } String result = responseSb.toString(); log.info("responseBody = {}", result); JsonParser parser = new JsonParser(); JsonElement element = parser.parse(result); JsonObject properties = element.getAsJsonObject().get("properties").getAsJsonObject(); JsonObject kakao_account = element.getAsJsonObject().get("kakao_account").getAsJsonObject(); String nickname = properties.getAsJsonObject().get("nickname").getAsString(); String profile_image = properties.getAsJsonObject().get("profile_image").getAsString(); String email = kakao_account.getAsJsonObject().get("email").getAsString(); userInfo.put("nickname", nickname); userInfo.put("email", email); userInfo.put("profile_image", profile_image); User user = new User(); user.setUseremail(email); user.setUsername(nickname); user.setOauthtype("kakao"); user.setOauthtoken("00000"); user.setUserphone("01033356803"); user.setUserbirthday("19960627"); System.out.println("user!!!!!!!" + user); repository.save(user); br.close(); } catch (Exception e) { e.printStackTrace(); } return userInfo; } }
LoginController
package com.cm.personalProject.controller; import java.util.Map; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import com.cm.personalProject.service.KakaoAPI; import lombok.AllArgsConstructor; import lombok.extern.log4j.Log4j2; @Log4j2 @AllArgsConstructor @RequestMapping(value = "/social") @Controller public class LoginController { private KakaoAPI kakao; @GetMapping("/loginPage") public void getLoginPage() { } @GetMapping("/login") public String login(@RequestParam("code") String code) { System.out.println(code); String access_token = kakao.getAccessToken(code); System.out.println("controller access_token : " + access_token); Map<String, Object> userInfo = kakao.getUserInfo(access_token); //System.out.println(userInfo.get("username")); //System.out.println(userInfo.get("useremail")); //System.out.println(userInfo.get("userphone")); System.out.println("nickname : " + userInfo.get("nickname")); return "home"; } }
'Spring Boot' 카테고리의 다른 글
[무한댓글 게시판] 2. Entity / Repository / Service + QueryDSL 사용 (0) 2024.02.15 [무한댓글 게시판] 1. 테이블 설계(+테이블 생성) (0) 2024.02.09 [Google Login] 구글 로그인 구현하기 (토큰 & 회원정보) (1) 2024.01.26 [Naver Login] 네이버 로그인 구현하기 (토큰 & 회원정보 담아오기 / 로그아웃) (1) 2024.01.24 [Kakao Login] 카카오 로그인 구현하기 (토큰 / 정보 받아오기 / 회원가입 - 로그인) (0) 2024.01.18