[React]카카오 REST API 로그인_TS
2021. 9. 17. 16:00ㆍWeb_Programming/React
소셜 로그인 중 가장 대표적으로 사용되는 것이 카카오 로그인입니다.
개발 문서도 자세히 나와있어서, 저도 카카오 로그인을 택했습니다
다만 보안 강화를 위해서 JWT를 추가적으로 이용하였습니다 :-D
카카오 로그인
토큰
Access Token | 사용자를 인증합니다. | Android, iOS : 12시간 JavaScript: 2 시간 REST API : 6시간 |
Refresh Token | 일정 기간 동안 다시 인증 절차를 거치지 않고도 액세스 토큰 발급을 받을 수 있게 해 줍니다. | 2달 유효기간 1달 남은 시점부터 갱신 가능 |
로그인 구현
토큰을 이용한 로그인의 전체적인 흐름은 다음과 같습니다.
- 로그인 ➞ 인가코드 발급
- 인가 코드 ➞ 토큰 발급(access, refresh)
- access 토큰을 서버로 넘겨 사용자 인증 후 DB 저장 ➞ JWT 토큰 발급
- JWT 토큰 localStorage에 저장 후, 자동 로그인 처리
+ 초기 로그인 시에만, 카카오 user정보를 받고 나머지는 JWT토큰을 이용하였기 때문에 access 토큰만 사용하였습니다.
💡 로그인 버튼 생성
+ 로그인 버튼은 kakao Dev 사이트에서 제공되고 있습니다.
로그인 버튼의 url은 에 아래와 같이 설정해줍니다.
`https://kauth.kakao.com/oauth/authorize?client_id=${내 애플리케이션 REST KEY}&redirect_uri=${카카오에서 설정한 redirect URI}&response_type=code`
import * as React from 'react';
const Login = () => {
const kauthUrl=`https://kauth.kakao.com/oauth/authorize?client_id=${process.env.REACT_APP_KAKAO_REST_KEY}&redirect_uri=${카카오에서 설정한 redirect URI}&response_type=code`
return (
<Link href={kauthUrl}>
<Image
src="/assets/kakao_login.png"
id="kakao-login-btn"
width="250"
height="100"
alt="kakao"
/>
</Link>
);
};
💡 코드 받기
로그인 버튼 클릭 후, 인증이 제대로 되었다면, redirect URI 파라미터로 코드값이 생성됩니다.
code : 토큰 받기 요청에 필요한 인가 코드
인가 코드값만 얻어오기 위해 아래와 같이 전처리를 해줍니다.
query-string 패키지를 이용하여 쿼리를 decode 합니다.
const query = queryString.parse(window.location.search);
💡 토큰 받기
redirect로 넘어온 url 파라미터 code값이 있을 경우 👉 getKakaoTokenHandler를 통해 토큰을 발급합니다.
const Login = () => {
const kauthUrl=`https://kauth.kakao.com/oauth/authorize?client_id=${process.env.REACT_APP_KAKAO_REST_KEY}&redirect_uri=http://localhost:3000/auth&response_type=code`
const query = queryString.parse(window.location.search);
React.useEffect(() => {
if (query.code) {
getKakaoTokenHandler(query.code.toString());
}
}, [query.code]);
const getKakaoTokenHandler = async (code:string) => {
try{
const data:any = {
grant_type: "authorization_code",
client_id: process.env.REACT_APP_KAKAO_REST_KEY,
redirect_uri: "redirect URI 입력",
code: code
};
const queryString = Object.keys(data)
.map((k:any)=> encodeURIComponent(k) + '=' + encodeURIComponent(data[k]))
.join('&');
//토큰 발급 REST API
const {data} = await axios.post('https://kauth.kakao.com/oauth/token', queryString, {
headers: {
'Content-type': 'application/x-www-form-urlencoded;charset=utf-8'
}
}
//서버에 전달
sendKakaoTokenToServer(data.access_token)
}catch(e){
console.error(e)
}
}
return (
<Link href={kauthUrl}>
<img src="kakao_login.png" id="kakao-login-btn" width="250px" />
</Link>
);
};
💡 JWT 토큰 받기
발급받은 access 토큰을 서버로 넘기고, 서버에서 JWT 토큰 값(추가로 user정보)을 받아 localstorage에 저장해둡니다.
const sendKakaoTokenToServer = async (token:string ) => {
const res = await axios.post('/auth/kakao',{access_token: token})
if (res.status == 201 || res.status == 200) {
const user =res.data.user;
window.localStorage.setItem("token", JSON.stringify({
access_token: res.data.jwt
}));
}else {
window.alert("로그인에 실패하였습니다.");
}
}
이렇게 JWT 토큰 까지 받았다면,
😉 로그인 완료 😉
+ 서버 측 카카오 로그인
+ (보완) Next 13, react-query 사용시 로그인 hooks 코드 예시
import { userInfoAtoms } from "@app/GlobalProvider";
import { useMutation } from "@tanstack/react-query";
import axios from "axios";
import { useSetAtom } from "jotai";
import { useResetAtom } from "jotai/utils";
import { useRouter, useSearchParams } from "next/navigation";
import { useEffect } from "react";
const useAuthKakao = () => {
const router = useRouter();
const searchParams = useSearchParams();
const query = searchParams?.get("code");
const setUserAtom = useSetAtom(userInfoAtoms.userAtom);
const resetUserAtom = useResetAtom(userInfoAtoms.userAtom);
const getKakaoToken = useMutation({
mutationFn: async (code: string) => {
const data = {
grant_type: "authorization_code",
client_id: process.env.NEXT_PUBLIC_KAKAO_REST_KEY || "",
redirect_uri: "http://localhost:3000/auth/login",
code,
};
const queryString = Object.keys(data)
.map((key) => `${key}=${data[key as keyof typeof data]}`)
.join("&");
return await axios.post(
"https://kauth.kakao.com/oauth/token",
queryString,
{
headers: {
"Content-type": "application/x-www-form-urlencoded;charset=utf-8",
},
}
);
},
onSuccess: (res: any) => {
putKakaoTokenToServer.mutate(res.data.access_token);
},
retry: false,
});
const putKakaoTokenToServer = useMutation({
mutationFn: async (token: string) => {
return await axios.put("/api/auth/kakao", {
access_token: token,
});
},
onSuccess: (res: any) => {
const { jwt, user } = res.data;
if (res.status == 201 || res.status == 200) {
setUserAtom(user);
window.localStorage.setItem(
"token",
JSON.stringify({
access_token: jwt,
})
);
axios.defaults.headers.common["Authorization"] = `${jwt}`;
router.push("/home");
} else {
window.alert("로그인에 실패하였습니다.");
resetUserAtom();
}
},
});
useEffect(() => {
if (query) {
getKakaoToken.mutate(query);
}
}, [query]);
return {
isLoading: getKakaoToken.isLoading || putKakaoTokenToServer.isLoading,
};
};
export default useAuthKakao;
반응형
'Web_Programming > React' 카테고리의 다른 글
React-query 알아보고 사용해보기 (0) | 2022.11.13 |
---|---|
리액트 타입스크립트_개념&사용법 (0) | 2021.10.11 |
[React.js]리액트_redux-saga (0) | 2021.08.03 |
[React.js]리액트 react-redux, reselect라이브러리 (0) | 2021.07.30 |
[React.js] 리덕스(액션,미들웨어, 리듀서, 스토어) (0) | 2021.07.21 |