Spring Boot

[Kakao Login] 카카오 로그인 구현하기 (토큰 / 정보 받아오기 / 회원가입 - 로그인)

어코링 2024. 1. 18. 15:55
  • 카카오 로그인에서 토큰에서 id 값 받아오기
  • 불러온 id값으로 oauthtype, oauthtoken 을 복합키로 구성함.
  • 중복 검사 (Optional<User>로 검사하여 만약 중복된 OauthId 객체가 있을 경우 로그인 하게 됨. 없으면 회원가입과 로그인 동시에 하는 것임.)
  • import 잘못해서 고생좀 했음 ;; import 할 때 어디서 import 되는지 잘 보고 하도록

KakaoAPI

package com.se.social.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.Optional;

import org.springframework.stereotype.Service;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.se.social.domain.OauthId;
import com.se.social.entity.User;
import com.se.social.repository.UserRepository;

import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;

@Log4j2
@Service
@RequiredArgsConstructor
public class KakaoAPI {

	private final UserRepository repository;

	// getToken
	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 String getUserInfo(String access_token) {
	    
	    String reqUrl = "https://kapi.kakao.com/v2/user/me";
	    try{
	        URL url = new URL(reqUrl);
	        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
	        conn.setRequestMethod("POST");
	        
	        // 요청에 필요한 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 email = kakao_account.getAsJsonObject().get("email").getAsString();
            String token_id = element.getAsJsonObject().get("id").getAsString();

            Optional<User> opt_user = repository.findById(new OauthId("kakao", token_id));

            if (!opt_user.isPresent()) {
            	User user = new User();
            	user.setUseremail(email);
            	user.setUsername(nickname);
            	user.setOauthtype("kakao");
            	user.setOauthtoken(token_id);
            	System.out.println("user!!!!!!!" + user);
            	repository.save(user);
            } 
       
	        br.close();
	        
	        return "success";

	    }catch (Exception e){
	        e.printStackTrace();
	        
	        return "fail";
	    }
	} // getUserInfo
	    
	
}

 

OauthId (복합키 설정)

package com.se.social.domain;

import java.io.Serializable;

import javax.persistence.IdClass;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class OauthId implements Serializable {
	private static final long serialVersionUID = 1L; // 기본값(초기화)

	private String oauthtype;

	private String oauthtoken;

}

LoginController

package com.se.social.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.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() {
	}
	
	@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);
        
        if(kakao.getUserInfo(access_token).equals("success")) {
        	return "redirect:/home";
        } else {
        	return "redirect:/social/loginPage";
        }
	
	}
	

}

 

User

package com.se.social.entity;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.Table;
import javax.persistence.Transient;

import com.se.social.domain.OauthId;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Entity
@Table
@Data
@AllArgsConstructor
@NoArgsConstructor
@IdClass(OauthId.class)
public class User implements Serializable {

	   @Transient
	   private static final long serialVersionUID = 1L; 

	   private String username;

	   @Id
	   private String oauthtype;
	   @Id
	   private String oauthtoken;
	   
	   private String useremail;
}

 

UserRepository

package com.cm.personalProject.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import com.cm.personalProject.domain.OauthId;
import com.cm.personalProject.entity.User;

public interface UserRepository extends JpaRepository<User, OauthId> {

}