DEV/WebProgramming

[React.js] 소셜 로그인 구현 - 카카오

9thxg 2023. 4. 28. 15:28

카카오 로그인

만약 사용한다면 가장 사용자가 많은 것 같은 카카오 서비스를 구현해 봤다.

 

Developer 사이트가 깔끔하게 정리되어 있어서 자료 찾기가 편했다.

 

 

 

출처:https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api

위 이미지는 카카오에서 제공하는 카카오 로그인에 대한 프로세스 흐름이다. 그래서 위 이미지와 비슷하게 프로세스를 구성하여 프로젝트에 구현하였다.

 

로그인에 대해서 처리하는 방법은 다양하지만 해당 프로젝트에서는 로그인을 처리할 페이지를 따로 만들고 그 페이지로 redirect 하여 로그인을 처리하는 방식을 사용했다.

 

 

 

플랫폼 등록

플랫폼 탭에서 현재 프로젝트가 실행되고 있는 도메인을 입력해 준다. 카카오 로그인 사용 시 REST API를 사용할 예정이므로 도메인은 https로 지정되어 있어야 정상적으로 사용가능하다. (localhost로 테스트하는 것은 사용이 가능하다)

 

타 소셜 로그인의 경우 필요한 상황이 생길 수 있으므로 배포 전에 확인하여 https로 도메인을 변경하는 것을 추천한다.

 

 

 

Redirect URI 설정

내 애플리케이션에서 카카오 로그인을 위한 애플리케이션을 추가해 주고 테스트나 적용할 redirect 경로를 설정해 준다. kakao_login이라는 페이지를 사용해서 처리하도록 했다.

 

상단 활성화 설정을 ON으로 변경해 주면 카카오 로그인을 사용할 수 있는 상태가 된다.

 

 

 

동의항목

추가적으로 카카오 로그인 탭에서 동의항목에서 로그인 유저에게서 필요한 항목을 설정한다.

 

사용자 개인 정보를 다루는 프로젝트를 하다 보니 개인 정보를 상당히 신중히 다루는 것을 알 수 있었다. 이전에는 "당연히 받을 수 있는 거 아니야?" 하던 내용들이 지금 보니 당연히 받아서 되는 것들이 아니었다. 이로 알 수 있듯이 카카오에서 사용자로부터 받아올 정보는 필요한 것만 설정하는 것이 좋다.(물론 테스트용으로 사용한다면 문제없다)

 

부득이하게 정보가 필요하다면 해당 정보가 왜 필요한지 카카오에게 전달해야 한다.

 

 

 

소셜 로그인이나 타 API 기능을 제공하는 기업의 경우 디자인 가이드라인 존재한다. 카카오 로그인의 경우에도 존재하기 때문에 필요하다면 카카오 로그인 탭에서 디자인 가이드에서 다운로드하여 사용한다.

 

 

 

//.env
VITE_KAKAO_LOGIN_CLIENT_ID= kakaologinclientid
VITE_KAKAO_LOGIN_REDIRECT_URI= https://redirecturi/kakao_login

키를 어떻게 고민이 있었지만 기존 프로젝트에 .env파일로 키를 관리하고 있어 해당 파일을 gitignore에 추가하고 사용했다.

 

REST API를 통해 통신하기 위한 키를 요약정보 탭에서 확인하여 저장하고 Redirect URI는 지정한 URI로 저장한다.

 

 

 

// Login.jsx
const Login = (props) => {
    //...
    
    const onClickKakao = () => {
        window.location.href = `https://kauth.kakao.com/oauth/authorize?client_id=${
            import.meta.env.VITE_KAKAO_LOGIN_CLIENT_ID
        }&redirect_uri=${
            import.meta.env.VITE_KAKAO_LOGIN_REDIRECT_URI
        }&response_type=code`;
    };

    //...

    return(
        <LoginBlock>
            {/* ... */}
            <div className="mt-4 text-center">
                <h5 className="font-size-14 mb-3">
                    소셜 로그인
                </h5>
                <div>
                    <div
                        className="kakaoLogin"
                        onClick={onClickKakao}
                    >
                        <img src={kakaoLogo} />
                    </div>
                </div>
            </div>
            {/* ... */}
        </LoginBlock>
    )
}

먼저 onClickKakao 함수를 통해 로그인 요청을 할 수 있도록 한다. vite의 경우는 환경 변수를 사용하기 위해 import.meta.VITE_환경변수명 식으로 사용한다.

 

REST API 방식이기 때문에 onClickKakao 함수에서 요청할 URL링크를 지정해 주고 query string에 환경변수에 저장해 뒀던 키와 redirect uri를 넣어준다.

 

로그인 버튼을 배치하고 onClick함수에 onClickKakao 함수를 바인딩해 주면 로그인 페이지는 완료다.

 

 

 

// KakaoLogin.jsx
const KakaoLogin = () => {
    //...
    //Loader 관련 State 
    
    useEffect(() => {
        const code = window.location.search.split("=")[1];

        const onKakaoLogin = async () => {
            try {
                const body = {
                    // body
                };
                const res = await apiKakaoLogin(body);

                if (res.state === 200) {
                    // api 응답이 성공적이라면 처리할 코드
                }
            } catch (e) {
                // 오류 처리
            }
        };

        if (code) {
            onKakaoLogin();
        }
    }, [])


    return (
        <KakaoLoginComponentBlock>
            {/* Loader를 띄울 수 있도록 함 */}
        </KakaoLoginComponentBlock>
    )
}

요청 키를 통해 카카오 서버로 요청을 보내고 카카오에서 유저 정보에 대한 요청을 할 수 있는 인가 코드를 다시 query string으로 던져준다. window 객체의 location 값을 통해 query string의 토큰 값을 찾아 저장해 주고 이를 백엔드로 전달하여 백엔드에서 유저 정보를 받아 올 수 있도록 하였다.

 

서비스 서버에서 인가 코드에 대한 처리가 이루어지는 것이 권장되기 때문에 위와 같이 구현했다.

 

 

 

// 백엔드 코드
// 로그인(social_kakao)
export const kakao = async (ctx) => {
    let { code, flag, social_id, userid, n_name, e_mail } = ctx.request.body;

    try {
        if (flag === "CHECK") {
            const response = await axios.post(
                "https://kauth.kakao.com/oauth/token",
                // 인코딩이 없으면 KOE010 에러 발생.
                // post로 body에 항목을 전달할때 인코딩이 필요함.
                formUrlEncoded({
                    grant_type: "authorization_code",
                    client_id: process.env.CLIENT_ID, // 앱 키
                    redirect_uri: process.env.KAKAO_REDIRECT_URL, // 요청이 성공한 경우 이동할 주소
                    code: code, // 인가코드
                    client_secret: process.env.CLIENT_SECRET, // 보안용 코드
                }),
                {
                    headers: {
                        "Content-type": "application/x-www-form-urlencoded", // 고정
                    },
                }
            );

            const { access_token } = response.data;

            const userInfo = await axios.get(
                "https://kapi.kakao.com/v2/user/me",
                {
                    headers: {
                        Authorization: `Bearer ${access_token}`,
                    },
                }
            );
            
            // 전달 받은 데이터 변수 저장
            social_id = userInfo.data.id;
            n_name = userInfo.data.properties.nickname;
            e_mail = userInfo.data.kakao_account.email;
        }

        // DB 저장
        const sql =
            "select * from TABLE ($1...)";
        const values = [
            Value...
        ];
        
        const retVal = await client.query(sql, values);
        
        let user_id;

        if (retVal.rows[0].result_code === "OK") {
            ctx.status = 200;
            // 카카오 로그인 성공 처리
        } else {
            ctx.status = 200;
            // 카카오 로그인 실패 처리
        }
    } catch (e) {
        ctx.status = 400;
        console.error(e);
        // 오류 핸들링
    }
};


백엔드는 구현 방식에 따라 달라질 수 있다. 해당 프로젝트에서 다음과 같이 사용했다.

 

카카오 서버와 통신하는 곳의 주석은 스승님이 작성한 내용이다. 앞서 프론트에서 사용자 로그인 페이지까지 인도하여 카카오로부터  인가 코드 값을 받아왔다. 그 코드 값을 이용해서 백엔드에서 액세스 토큰을 발급받고 발급받은 액세스 토큰을 통해 유저의 정보를 열람할 수 있게 된다.

 

열람을 통해 유저 정보에 대한 조회와 저장이 완료되었다면 DB에 저장을 처리하고 프론트에 응답을 보낼 수 있도록 하였다. 


이로서 카카오 로그인을 구현해 봤다. 카카오 로그인은 스승님이 구현한 부분이라 구현할 당시에는 깊이 이해하지 못했는데 다른 소셜 로그인들을 구현해 가며 점점 이해하게 되었고 그 이해를 바탕으로 글을 쓰게 되었다.

 

블로그 글을 쓰며 정보를 찾다가 알게 되었는데 카카오 로그인도 Javascript SDK가 존재하기 때문에 위와 같은 방식 외 SDK를 사용하여 구현할 수 있다는 것이다. 구현 방식의 차이가 있을 뿐 크게 차이가 없다고 생각한다

 

앞서 이야기했듯이 개인 정보에 대해서 굉장히 신중히 다루기 때문에 배포를 고려하고 있다면 꼭 필요한 정보만 받아 사용해야 한다. 추가적으로 로그인뿐만 아니라 카카오 biz와 같은 많은 기능들이 포함되어 있기 때문에 기회가 된다면 사용해 보는 것도 좋아 보인다.

 

React.js에서 카카오 로그인을 구현하는 과정이었다. 해당 내용을 구현했을 때는 어렵게 다가온 내용이었지만 막상 구현해 놓고 정리해 보니 그렇게 어려운 것이 아니었다. 프로그래밍이라는 것이 그렇지 않을까 싶은 생각이 든다.

다음은 구글 로그인 구현에 대해서 글을 써볼 예정이다.