Therapist

Spring boot + React + Kakao Login 연동하기

그래놀라_ 2021. 8. 29. 01:30

Kakao Developers에 도메인 주소 : 프론트 http://localhost:3000으로 설정되어 있어야함

  1. 프론트 서버에서 http://localhost:3000 접속 후 카카오 로그인 하면 인가 code를 받아 access token을 발급 받고 백엔드로 전달
  2. 전달 받은 access token을 가지고 카카오로부터 사용자 정보 받아와 우리 DB에 저장 ( ID: 카카오 이메일, PW: 임의 문자열 )
  3. 우리 DB에 저장된 사용자 정보를 가지고 JWT 토큰 생성 후 프론트로 전달
  4. 프론트에서 localStorage에 JWT 토큰 저장
  5. 추후 API 사용시 헤더에 JWT 토큰 포함해 요청

# Kakao Developers 설정

  1. 앱 도메인 프론트엔드 주소로 설정 http://localhost:3000
  2. Redirect URI 설정 http://localhost:8080/auth/kakao/callback
  3. 카카오 로그인 활성화 On

 

# 프론트엔드 설정

 1  JavaScript SDK 적용 및 초기화

public/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    						:
    <script src="https://developers.kakao.com/sdk/js/kakao.js"></script>
    <script>Kakao.init('JAVASCRIPT_KEY');</script>

    <title>Therapist</title>
</head>
<body>
    <main id="root"></main>
    <div id="modal"></div>
</body>
</html>

Kakao Developers에 등록한 앱의 JAVA SCRIPT 키를 이용하여 SDK 초기화 

 

https://developers.kakao.com/docs/latest/ko/getting-started/sdk-js

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

 

 2  리액트 컴포넌트에서 Kakao API 요청으로 카카오 로그인 처리

  • 브라우저의 window 객체에서 Kakao API 가져오기 const { kakao } = window;
    • 리액트 컴포넌트 상단에 아래 코드를 작성하여 Kakao api 에 접근할 수 있다.
  • Kakao.Auth.login 함수를 사용하여 카카오 로그인 팝업창 출력 및 로그인 처리
    • 클릭 이벤트 핸들러에서 Kakao.Auth.login 함수를 호출하면 카카오 로그인 동의화면 띄울 수 있으며, 동의화면을 통해 사용자로부터 사용자 정보 및 기능 활용 동의를 받을 수 있다.
    • 인가된 사용자일 경우 success 콜백함수를 사용해 카카오 사용자 토큰을 받아옴
    • 로그인 성공 후 fetch 함수를 이용해 카카오에서 보내준 카카오 사용자 토큰 access_token 을 백엔드 서버로 보냄 (카카오앱에 등록해둔 Redirect URI)
    • 백엔드단에서 access_token을 가지고 카카오로 사용자 정보를 요청 후 받아와 MariaDB에 저장하고 JWT 토큰 만들어 프론트단으로 반환
    • 받아온 JWT 토큰을 프론트단에서 localStorage에 저장
    • 마지막으로 history.push 함수를 사용해서 이동시키고자 웹 페이지로 보내준다.
import React, { useState } from 'react';
import { withRouter, Link } from 'react-router-dom';
import ModalPortal from '../../../../portal/ModalPortal.js';
import { useHistory } from "react-router-dom";

import './RightMenu.css';

const { kakao } = window;

function RightMenu() {
    
    const history = useHistory();
    const kakaoLoginClickHandler = () => {
        Kakao.Auth.login({
            success: function (authObj) {
                fetch(`${"http://localhost:8080/auth/kakao/callback?accessToken="+authObj.access_token}`, {
                    method: "GET",
                })

                .then(res => res.json())
                .then(res => {
                    localStorage.setItem("token", res.token);
                    if (res.access_token) {
                        alert("welcome")
                        history.push("/");
                    }
                })
            },
            fail: function (err) {
                alert(JSON.stringify(err))
            }
        })
    };

    return (
        <Button fill className="btn kakao" onClick={kakaoLoginClickHandler}>카카오 로그인</Button>
    );
};

export default RightMenu;

https://velog.io/@seize/React-%EC%B9%B4%EC%B9%B4%EC%98%A4-%EC%86%8C%EC%85%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8

 

[React] 카카오 소셜 로그인

이번 프로젝트에서 카카오 소셜 로그인을 맡게 되었다. 소셜 로그인 중 카카오가 가장 쉽다고 한다. 그 이유는 카카오 개발자 사이트에서 사용 가이드를 친절하게 작성해놓았기 때문이라고 한

velog.io

https://developers.kakao.com/docs/latest/ko/kakaologin/js

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

 

# 백엔드 설정

 1  받아온 Access token으로 사용자 처리 / 생성한 JWT토큰 반환

AuthController

  • 받아온 토큰을 requestKakaoUserInfo 함수로 보내 카카오 사용자 정보를 처리하여 userMap에 담는다.
    • ID : kakao_email
    • PW : 랜덤 문자열
  • userMap으로 받아온 사용자 정보로 UserDto생성하여 /account/register API 요청으로 우리 DB에 저장
    • 이 때 password Encoding 하여 DB에 저장
  • JWT토큰을 생성하기 위해 username과 password를 LoginDto에 담아 해당 API로 보냄
  • 반환받은 JWT토큰({"token": "ey ~~"} <type: String>)을 JSONObject에 담아 프론트로 전달
@CrossOrigin("*")
@GetMapping("/kakao/callback")
public JSONObject kakaoCallback(String accessToken) throws ParseException { // @ResponseBody : Data를 리턴해주는 컨트롤러 함수
  Map<String, String> userMap = userService.requestKakaoUserInfo(accessToken);
  System.out.println("accessToken: "+accessToken);
  RestTemplate rt = new RestTemplate();

  // builder 이용하여 UserDto 필드 초기화
  UserDto newUser = UserDto.builder()
    .userName(userMap.get("username"))
    .userPassword(userMap.get("password"))
    .userProfileImage(userMap.get("profile_image"))
    .userThumbnailImage(userMap.get("thumbnail_image"))
    .userEnabled(true)
    .build();

  HttpEntity<UserDto> requestEntity = new HttpEntity<>(newUser);
  rt.exchange(
    "http://localhost:8080/account/register",
    HttpMethod.PUT,
    requestEntity,
    Void.class
  );

  LoginDto loginDto = LoginDto.builder()
    .username(userMap.get("username"))
    .password(userMap.get("password"))
    .build();

  String response = userService.requestPostWithFormData("/auth/authenticate", loginDto);
  JSONParser parser = new JSONParser();
  Object token = parser.parse(response);
  JSONObject res = (JSONObject) token;

  return res;
}

 

※ 나만 겪은 issue.. 

여기서 굉장히 헤맸는데, 처음에 제대로 다 했는데도 자꾸 KEO 320 에러가 났다 

아니 나는 계속 새롭게 카카오 로그인을 누르는데 어째서 두 번 이상 사용하게 된건가 했더니 

https://devtalk.kakao.com/t/topic/109348/4

 

코드 받고 토큰 요청 시 오류 발생

카카오 데브톡. 카카오 플랫폼 서비스 관련 질문 및 답변을 올리는 개발자 커뮤니티 사이트입니다.

devtalk.kakao.com

이 글을 보고 다시 코드를 보니 애초에 프론트에서 인가 code를 받아 백으로 보내주는게 access token인데 나는 받아오는게 인가코드인줄 알고 access token으로 access token을 또 받아오려고 했던것..ㅋㅋ 삽질은 언제나 이상한데서ㅠ

// 변경 전
public ResponseEntity<String> kakaoCallback(String code) { // @ResponseBody : Data를 리턴해주는 컨트롤러 함수
	String accessToken = userService.getAccessToken(code);
    Map<String, String> userMap = userService.requestKakaoUserInfo(accessToken);
    
    
// 변경 후 
public JSONObject kakaoCallback(String accessToken) throws ParseException { // @ResponseBody : Data를 리턴해주는 컨트롤러 함수
    // 프론트에서 Kakao 서버로 인증코드 받아 인증된 사용자면 access token을 보내옴
    Map<String, String> userMap = userService.requestKakaoUserInfo(accessToken);

 

 

 

+ CORS 이슈

public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedOrigins("*");
    }
}