본문 바로가기
SPA/Next

[Next] Kakao 로그인 Spring을 활용하여 구현하기

by J4J 2023. 3. 26.
300x250
반응형

안녕하세요. J4J입니다.

 

이번 포스팅은 kakao 로그인 spring을 활용하여 구현하는 방법에 대해 적어보는 시간을 가져보려고 합니다.

 

 

 

들어가기에 앞서

 

동일한 방식의 다른 서비스 로그인을 활용하는 방법에 대해 궁금하신 분들은 다음을 참고해 주시면 됩니다.

 

[Next] Naver 로그인 Spring을 활용하여 구현하기

[Next] Apple 로그인 Spring을 활용하여 구현하기

 

 

 

Next만을 이용하여 kakao 로그인을 구현하는 방법에 대해 궁금하신 분들은 다음을 참고해주시면 됩니다.

 

[Next] 카카오 로그인 구현하기

 

 

반응형

 

 

애플리케이션 등록

 

kakao를 이용하여 로그인을 구현하기 위해서는 먼저 사용하려는 서비스 애플리케이션 정보를 등록해줘야 합니다.

 

다음 절차들을 통해 설정해보도록 하겠습니다.

 

 

 

[ 1. kakao developer 접속 ]

 

https://developers.kakao.com

 

Kakao Developers

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

developers.kakao.com

 

 

 

[ 2. 내 애플리케이션 접속 ]

 

내 애플리케이션

 

 

 

[ 3. 애플리케이션 추가하기 ]

 

애플리케이션 추가하기

 

 

 

애플리케이션 추가하기를 누르면 아래와 같은 화면이 나옵니다.

 

정보들을 모두 입력하고 저장을 눌러주면 다음과 같이 애플리케이션이 추가되는 것을 확인할 수 있습니다.

 

애플리케이션 정보 입력

 

애플리케이션 생성 확인

 

 

 

 

[ 4. 사이트 도메인 등록 ]

 

애플리케이션에 사용될 사이트 도메인을 등록해 주겠습니다.

 

생성한 애플리케이션을 클릭한 뒤 좌측 메뉴에 플랫폼을 선택하고 Web 플랫폼 등록 버튼을 클릭해 줍니다.

 

Web 플랫폼 등록하기

 

 

 

그러면 다음과 같이 도메인을 등록하는 화면이 나오는데 여기에 사용하실 도메인을 입력해 주시면 됩니다.

 

사이트 도메인 등록

 

 

 

추가 참고사항으로 개발을 하다 보면 등록되어야 할 도메인이 로컬 도메인, 개발 도메인, 운영 도메인까지 최소 3개가 될 것입니다.

 

그럴 땐 다음과 같이 개행을 통해 입력을 해주시면 되고, 첫 번째 작성한 도메인이 기본 도메인이 되기 때문에 기본 도메인을 운영 도메인으로 설정해 주시면 됩니다.

 

다른 도메인을 추가하는 경우

 

 

 

 

[ 5. Redirect URI 등록하기 ]

 

Redirect URI는 로그인이 성공적으로 이루어졌을 때 카카오에서 결괏값을 담은 데이터를 넘겨주는 우리가 개발할 서비스 경로입니다.

 

 

 

먼저 도메인을 등록한 정보 아래에 있는 등록 하러 가기 링크를 클릭해 줍니다.

 

Redirect URI 등록하러 가기

 

 

 

링크를 클릭하면 나오는 화면에서는 먼저 활성화 설정 상태를 ON으로 변경해 줍니다.

 

활성화 설정 ON

 

 

 

그리고 스크롤을 아래로 내려서 Redirect URI 등록 버튼을 클릭하여 다음과 같이 등록해 줍니다.

 

등록되는 URI는 위에서 등록했던 도메인을 기준으로 추가 경로를 입력해 주시면 됩니다.

 

Redirect URI 등록

 

Redirect URI 추가

 

 

 

Redirect URI 부분도 도메인 등록할 때와 동일합니다.

 

로컬, 개발, 운영까지 최소 3개의 URI이 등록될 것이며 이럴 땐 다음과 같이 개행을 통해 입력해주시면 됩니다.

 

다른 Redirect URI를 추가하는 경우

 

 

 

[ 6. 개인정보 동의 항목 설정 ]

 

개인정보 동의 항목 같은 경우는 사용자가 로그인을 했을 때 개발자가 활용할 수 있는 정보들을 등록하는 곳입니다.

 

좌측 메뉴에 동의항목을 선택한 뒤 활용하기 원하는 정보들을 다음과 같이 설정해 주시면 됩니다.

 

그리고 일부 필수 동의가 되지 않는 항목들이나 동의 선택이 불가한 항목들은 카카오 싱크 등과 같은 추가 작업을 진행하면 추가 변경할 수 있는 항목들이 있으니 필요하신 분들은 참고하시면 될 것 같습니다.

 

개인정보 동의 항목 설정

 

 

 

[ 7. 애플리케이션 앱 키 확인 ]

 

모든 설정이 끝났으면 좌측 메뉴에서 요약 정보를 선택하여 애플리케이션 앱 키들을 확인해 줍니다.

 

여기에 보이는 앱 키들은 코드를 구현할 때 사용되는 값들이며 다른 사용자들에게 노출되면 악의적으로 사용될 수 있으니 웬만하면 키가 노출되지 않게 해 주시는 게 좋을 것 같습니다.

 

애플리케이션 앱 키 정보 확인

 

 

 

 

Next

 

모든 설정이 완료되었다면 Next 쪽 코드를 구현해 보겠습니다.

 

먼저 로그인 버튼이 보일 페이지에 다음과 같이 코드를 작성해 줄 수 있습니다.

 

import Head from 'next/head';

const Index = () => {
    /**
     * handle
     */
    const handle = {
        clickKakaoLogin: () => {
            const clientId = '77ec86776bd405c9dc07c04db6e697a8'; // 앱 키 중 JavaScript 키
            const redirectUri = 'http://localhost:8088/kakao/login'; // 등록한 Redirect URI

            location.href = `https://kauth.kakao.com/oauth/authorize?response_type=code&client_id=${clientId}&redirect_uri=${redirectUri}`;
        },
    };

    return (
        <>
            <Head>
                <title>kakao login</title>
            </Head>

            <div>
                <button onClick={handle.clickKakaoLogin}>카카오 로그인</button>
            </div>
        </>
    );
};

export default Index;

 

 

 

그리고 로그인이 완료된 후 redirect가 되는 페이지에는 다음과 같이 코드를 작성해줄 수 있습니다.

 

import axios from 'axios';
import { useRouter } from 'next/router';
import { useEffect } from 'react';

interface KakaoLogin {
    code: string;
}

const Login = () => {
    /**
     * router
     */
    const router = useRouter();

    /**
     * useEffect
     */
    useEffect(() => {
        if (router.isReady) {
            const code = router.query.code as string; // 카카오에서 query문자열로 넘겨준 로그인 code값 추출
            console.log(`code= ${code}`);
            login(code);
        }
    }, [router.isReady]);

    /**
     * login
     */
    const login = async (code: string) => {
        const kakaoLogin: KakaoLogin = {
            code,
        };

        const res = await axios.post('http://localhost:8080/api/kakao/login', kakaoLogin); // 스프링 API서버에 code값을 담아 로그인 요청
        if (res.data) {
            console.log(res.data);
        }
    };

    return <></>;
};

export default Login;

 

 

 

 

SpringBoot

 

다음은 SpringBoot 코드를 작성해 보겠습니다.

 

SpringBoot에서는 로그인을 위한 controller 구성을 해주시면 됩니다.

 

controller에 의해 만들어지는 api의 역할은 다음과 같습니다.

 

  • code값을 이용하여 kakao token값 확인
  • kakao token값을 이용하여 로그인 사용자 정보 추출

 

 

 

코드는 다음과 같이 작성해 보겠습니다.

 

package com.kakao.login.controller;

import com.kakao.login.dto.KakaoLogin;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;

import java.util.HashMap;
import java.util.Map;

@RestController
@CrossOrigin("*")
public class KakaoLoginController {

    private String kakaoUrl = "https://kauth.kakao.com";
    private String kakaoApiUrl = "https://kapi.kakao.com";
    private String clientId = "6fd6a723923f45ee818dc814ec14a844"; // 앱 키 중 REST API 키

    @PostMapping("/api/kakao/login")
    public ResponseEntity<Object> kakaoLogin(@RequestBody KakaoLogin kakaoLogin) {
        /**
         * code값을 이용하여 token정보 가져오기
         */
        // webClient 설정
        WebClient kakaoWebClient =
                WebClient.builder()
                        .baseUrl(kakaoUrl)
                        .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                        .build();

        // token api 호출
        Map<String, Object> tokenResponse =
                kakaoWebClient
                        .post()
                        .uri(uriBuilder -> uriBuilder
                                .path("/oauth/token")
                                .queryParam("grant_type", "authorization_code")
                                .queryParam("client_id", clientId)
                                .queryParam("code", kakaoLogin.getCode())
                                .build())
                        .retrieve()
                        .bodyToMono(Map.class)
                        .block();

        String accessToken = (String) tokenResponse.get("access_token");

        /**
         * accessToken으로 로그인 사용자가 동의한 정보 확인하기
         */
        // webClient 설정
        WebClient kakaoApiWebClient =
                WebClient.builder()
                        .baseUrl(kakaoApiUrl)
                        .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                        .build();

        // info api 설정
        Map<String, Object> infoResponse =
                kakaoApiWebClient
                        .post()
                        .uri(uriBuilder -> uriBuilder
                                .path("/v2/user/me")
                                .build())
                        .header("Authorization", "Bearer " + accessToken)
                        .retrieve()
                        .bodyToMono(Map.class)
                        .block();

        Map<String, Object> kakaoAccountMap = (Map<String, Object>) infoResponse.get("kakao_account");
        Map<String, String> profileMap = (Map<String, String>) kakaoAccountMap.get("profile");
        Map<String, String> responseMap = new HashMap<>();

        // 닉네임 정보 담기
        if (StringUtils.hasText(profileMap.get("nickname"))) {
            responseMap.put("nickname", profileMap.get("nickname"));
        }
        // 프로필 사진 정보 담기
        if (StringUtils.hasText(profileMap.get("profile_image_url"))) {
            responseMap.put("profileImageUrl", profileMap.get("profile_image_url"));
        }
        // 이메일 정보 담기
        if ("true".equals(kakaoAccountMap.get("has_email").toString())) {
            responseMap.put("email", kakaoAccountMap.get("email").toString());
        }
        // 성별 정보 담기
        if ("true".equals(kakaoAccountMap.get("has_gender").toString())) {
            responseMap.put("gender", kakaoAccountMap.get("gender").toString());
        }
        // 연령대 정보 담기
        if ("true".equals(kakaoAccountMap.get("has_age_range").toString())) {
            responseMap.put("ageRange", kakaoAccountMap.get("age_range").toString());
        }
        // 생일 정보 담기
        if ("true".equals(kakaoAccountMap.get("has_birthday").toString())) {
            responseMap.put("birthday", kakaoAccountMap.get("birthday").toString());
        }

        // 결과 반환
        return ResponseEntity.ok(responseMap);
    }
}

 

 

 

 

테스트

 

코드를 작성한 뒤 서버를 실행하여 Client에 접속하면 다음과 같은 버튼을 확인할 수 있습니다.

 

Client 화면

 

 

 

카카오 로그인 버튼을 클릭하면 처음 로그인할 때만 다음과 같은 정보 제공 동의 화면을 확인할 수 있습니다.

 

정보 제공 동의 화면

 

 

 

 

정보 제공을 원하는 항목들을 선택한 뒤 동의하고 계속하기 버튼을 클릭하면 다음과 같이 redirect uri로 등록한 경로로 이동되며 아래와 같은 로그를 확인할 수 있습니다.

 

로그인 결과

 

 

 

첫 번째 로그인 code 값은 카카오 로그인을 한 뒤 경로가 이동될 때 query 문자열에 함께 담아 전달해 준 code값입니다.

 

두 번째 로그인 사용자 정보들은 전달받은 code값을 spring api 서버에 전달하여 사용자 정보를 추출한 뒤 client로 다시 전달해 준 정보입니다.

 

 

 

 

 

 

 

 

이상으로 kakao 로그인 spring을 활용하여 구현하는 방법에 대해 간단하게 알아보는 시간이었습니다.

 

읽어주셔서 감사합니다.

 

 

 

728x90
반응형

댓글