on
[React + Node.js] 카카오 로그인 API 이용하기
[React + Node.js] 카카오 로그인 API 이용하기
세종대왕님 만세. 한글로 된 문서가 새삼 반갑다.
문서에선 카카오 로그인이 진행되는 과정을 이렇게 표현하고 있다. 프론트에서 카카오 서버로 로그인을 요청하면 인가 코드가 발급된다.
그 인가 코드로 카카오 서버에 다시 요청해서 토큰을 받아와 사용한다.
먼저 Kakao Developers 에서 애플리케이션을 생성한다.
카카오 로그인 동의 항목, 도메인, 리다이렉트 URI 등을 설정하고 앱 키를 확인한다.
1트
노드 서버에서는 REST API를, 리액트 프론트에서는 자바스크립트 SDK를 사용해서 카카로 로그인을 해보려고 한다.
인가 코드 받기
1) CRA로 리액트 프로젝트를 시작하고 index.html의 헤더 부분에 Javascript SDK를 포함시킨다.
// 발급받은 앱 키를 넣고 초기화한다. Kakao.init("JAVASCRIPT 앱키"); Kakao.isInitialized();
2) 아래의 함수로 카카오 서버에 요청을 보낸다.
Kakao.Auth.authorize({ redirectUri: '{REDIRECT_URI}' });
redirect uri는 인가코드를 받을 URI이다. 내 서버에서 해당 경로의 라우팅을 설정해주었다. Kakao.Auth.authorize 함수에서 파라미터로 설정해준 ridirectUri와 카카오 개발자 페이지에서 설정한 ridirectUri가 다르면 오류를 반환한다.
토큰 받기
1) 설정한 리다이렉트 URI인 /app/kakao/callback 으로 요청이 들어오면 getToken 함수를 실행한다.
인가 코드는 쿼리스트링으로 담겨져 들어온다.
curl -v -X POST "https://kauth.kakao.com/oauth/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=authorization_code" \ -d "client_id={REST_API_KEY}" \ --data-urlencode "redirect_uri={REDIRECT_URI}" \ -d "code={AUTHORIZE_CODE}"
문서에 요청 샘플이 이렇게 적혀있다. 찾아보니까 -d 는 쿼리스트링의 형태로 데이터를 전달할 때 사용한다. URL 인코딩된 값을 보낼 때는 --data-urlencode 를 사용한다.
const axios = require("axios"); const secret_config = require("../../../config/secret"); module.exports = (app) => { app.get("/auth/kakao/callback", getToken, getKakaoUser); }; const getToken = async (req, res, next) => { try { const code = req.query.code; console.log(secret_config.kakaoRedirectUri); const token = await axios({ method: "POST", url: `https://kauth.kakao.com/oauth/token?grant_type=authorization_code&client;_id=${secret_config.kakaoRestApiKey}&redirect;_uri=${secret_config.kakaoRedirectUri}&code;=${code}`, headers: { "content-type": "application/x-www-form-urlencoded", }, }); req.kakaoToken = token.data; next(); } catch (err) { console.log(err.data); } };
2) REST API 키와 리다이렉트 URI를 따로 분리시킨 후에 불러와 사용했다. 인가코드와 함께 쿼리스트링에 담는다. 토큰은 응답의 data 객체에 담겨 있다. 해당하는 값을 찾아서 req.kakaoToken 에 저장했다.
3) next() 로 다음 미들웨어 함수를 실행한다.
사용자 정보 가져오기
accss token을 헤더로 담아 카카오 API에 요청을 보내 유저 정보를 가져온다.
const getKakaoUser = async (req, res) => { const accessToken = req.kakaoToken.access_token; try { const kakaoUser = await axios({ method: "GET", url: `https://kapi.kakao.com/v2/user/me`, headers: { Authorization: `Bearer ${accessToken}`, }, }); console.log(kakaoUser.data); } catch (err) { console.log(err.data); } };
응답으로 오는 데이터들은 이 링크에서 확인할 수 있다. 문서
이 다음에서 진도를 나가지 못하고 막혔다. 토큰을 서버에서 받아서 카카오 정보도 서버로 받아오긴 했는데, 그것들을 클라이언트로 보낼 수 있는 방법을 구하지 못했다. 서버가 아닌 프론트단에서 정보들을 받아와야 했던 것 같다.
2트
프론트에서 카카오 사용자 정보를 받은 후에, 그걸로 내 서버에 다시 요청을 보내는 식으로 다시 해보려고 한다.
npm에서 react-kakao-login 이라는 아주 편리한 패키지를 이용했다. npm
react-kakao-login
사용법이 매우 간단하다. 인가 코드, 토큰 발급과 같은 중간 과정들을 한번에 처리해준다.
import KakaoLogin from "react-kakao-login";
패키지를 import 하고 컴포넌트를 입력하면 된다. token에는 발급받은 javascript 앱 키를 넣어준다. 요청 성공, 실패 그리고 로그아웃의 경우에 실행할 함수를 넣어준다. 로그인 된 상태에서 버튼을 한번 더 누르면 로그아웃이 된다.
useLoginForm 속성을 넣으면 기기에 등록된 계정이 아닌 계정을 직접 입력할 수 있는 팝업 창이 뜨도록 할 수 있다.
style 속성으로 css를 적용할 수 있다.
응답 객체의 모습이다. 카카오 사용자의 고유 id, 이름, 프로필 이미지, 이메일이 담겨있다. 이름과 프로필 이미지까지는 필수 동의지만 이메일은 로그인할 때 직접 동의를 눌러주어야만 데이터를 가져올 수 있다.
카카오 사용자 정보 가져오기
onSuccess 일때 실행할 함수는 위와 같이 적어주었다. 응답 객체에서 값들을 가져와 context에서 관리하고 있는 상태에 저장한다.
토큰은 쿠키에 저장한다. 기한은 일단 아주 많이. universal-cookie 패키지를 이용한다.
{ console.log(res); cookies.set("kakaoAccess", res.response.access_token, { path: "/", maxAge: 60 * 60 * 24 * 30, }); context.setKakao({ name: res.profile.kakao_account.profile.nickname, email: res.profile.kakao_account.email, id: res.profile.id, image: res.profile.kakao_account.profile.profile_image_url, }); }} onFail={(err) => { console.log("로그인실패", err); }} onLogout={() => { console.log("로그아웃"); }} />;
회원가입
context의 kakao 객체에 값이 들어오는 것을 감지한 후에 이메일로 서버에 유저 검색을 요청한다. DB에 해당 사용자가 있으면 곧바로 로그인을, 사용자가 없으면 회원가입을 진행한다.
useEffect(() => { const myAccount = async () => { try { const response = await axios.get(`https://9yujin.shop/app/users?email=${context.kakao.email}`); console.log(response); if (response.data.result.length == 0) { setSignup(true); } else { //로그인 signin(); } } catch (err) { console.error(err); } }; if (context.kakao.email) { myAccount(); } }, [context.kakao]);
signup state가 true 가 되면 회원가입 컴포넌트를 렌더링하도록 되어있다.
사용자의 전화번호는 카카오 서버에서 가져올 수 있는 권한이 없다. 기존에 만들어 놓은 로그인 API를 이용하려면 전화번호를 필수록 입력해야 되기 때문에 추가 정보 입력 후에 회원가입을 할 수 있도록 했다.
로그인
DB에 이미 등록되어 있는 이메일로 로그인을 할 수 있다. 비밀번호를 따로 입력하지 않고도 로그인을 할 수 있어야 하는데, 고민을 하다가 카카오 사용자 고유 id를 비밀번호로 사용하기로 했다. 헤더에 카카오에서 발급 받은 토큰을 함께 담아서 보낸다. 서버에서는 그 토큰을 가지고 사용자 정보를 가져와 검증을 한 후에 로그인을 진행한다.
const signin = async () => { const token = cookies.get("KakaoAccess"); console.log(token); const loginResult = await axios({ method: "POST", url: `https://9yujin.shop/app/users/login`, data: { email: context.kakao.email, password: String(context.kakao.id), }, headers: { "Kakao-access-token": token, }, }); const loginData = loginResult.data.result; context.setUser({ name: loginData.userName, email: loginData.userEmail, image: loginData.userImage, phone: loginData.userPhone, wow: loginData.userWow, jwt: loginData.jwt, }); };
응답으로 온 데이터들을 user state에 저장한다. 프론트에서는 user state에 값이 들어오면 로그인 정보들을 렌더링 한다.
이렇게 카카오 로그인 기능을 내 서버에 이용할 수 있다.
from http://9yujin.tistory.com/14 by ccl(A) rewrite - 2021-12-30 16:00:34