๐จ ์ผ๋งค์ฃผ์
์ธ์ข ๋์๋ ๋ง์ธ. ํ๊ธ๋ก ๋ ๋ฌธ์๊ฐ ์์ผ ๋ฐ๊ฐ๋ค.
๋ฌธ์์์ ์นด์นด์ค ๋ก๊ทธ์ธ์ด ์งํ๋๋ ๊ณผ์ ์ ์ด๋ ๊ฒ ํํํ๊ณ ์๋ค. ํ๋ก ํธ์์ ์นด์นด์ค ์๋ฒ๋ก ๋ก๊ทธ์ธ์ ์์ฒญํ๋ฉด ์ธ๊ฐ ์ฝ๋๊ฐ ๋ฐ๊ธ๋๋ค.
๊ทธ ์ธ๊ฐ ์ฝ๋๋ก ์นด์นด์ค ์๋ฒ์ ๋ค์ ์์ฒญํด์ ํ ํฐ์ ๋ฐ์์ ์ฌ์ฉํ๋ค.
๋จผ์ Kakao Developers ์์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์์ฑํ๋ค.
์นด์นด์ค ๋ก๊ทธ์ธ ๋์ ํญ๋ชฉ, ๋๋ฉ์ธ, ๋ฆฌ๋ค์ด๋ ํธ URI ๋ฑ์ ์ค์ ํ๊ณ ์ฑ ํค๋ฅผ ํ์ธํ๋ค.
1ํธ
๋ ธ๋ ์๋ฒ์์๋ REST API๋ฅผ, ๋ฆฌ์กํธ ํ๋ก ํธ์์๋ ์๋ฐ์คํฌ๋ฆฝํธ SDK๋ฅผ ์ฌ์ฉํด์ ์นด์นด๋ก ๋ก๊ทธ์ธ์ ํด๋ณด๋ ค๊ณ ํ๋ค.
์ธ๊ฐ ์ฝ๋ ๋ฐ๊ธฐ
1) CRA๋ก ๋ฆฌ์กํธ ํ๋ก์ ํธ๋ฅผ ์์ํ๊ณ index.html์ ํค๋ ๋ถ๋ถ์ Javascript SDK๋ฅผ ํฌํจ์ํจ๋ค.
<script src="https://developers.kakao.com/sdk/js/kakao.js"></script>
<script>
// ๋ฐ๊ธ๋ฐ์ ์ฑ ํค๋ฅผ ๋ฃ๊ณ ์ด๊ธฐํํ๋ค.
Kakao.init("JAVASCRIPT ์ฑํค");
Kakao.isInitialized();
</script>
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;
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";
<KakaoLogin
token={"JAVASCRIPT KEY"}
onSuccess={}
onFail={}
onLogout={}
//useLoginForm
//style={{}}
/>
ํจํค์ง๋ฅผ import ํ๊ณ ์ปดํฌ๋ํธ๋ฅผ ์ ๋ ฅํ๋ฉด ๋๋ค. token์๋ ๋ฐ๊ธ๋ฐ์ javascript ์ฑ ํค๋ฅผ ๋ฃ์ด์ค๋ค. ์์ฒญ ์ฑ๊ณต, ์คํจ ๊ทธ๋ฆฌ๊ณ ๋ก๊ทธ์์์ ๊ฒฝ์ฐ์ ์คํํ ํจ์๋ฅผ ๋ฃ์ด์ค๋ค. ๋ก๊ทธ์ธ ๋ ์ํ์์ ๋ฒํผ์ ํ๋ฒ ๋ ๋๋ฅด๋ฉด ๋ก๊ทธ์์์ด ๋๋ค.
useLoginForm
์์ฑ์ ๋ฃ์ผ๋ฉด ๊ธฐ๊ธฐ์ ๋ฑ๋ก๋ ๊ณ์ ์ด ์๋ ๊ณ์ ์ ์ง์ ์
๋ ฅํ ์ ์๋ ํ์
์ฐฝ์ด ๋จ๋๋ก ํ ์ ์๋ค.
style
์์ฑ์ผ๋ก css๋ฅผ ์ ์ฉํ ์ ์๋ค.
์๋ต ๊ฐ์ฒด์ ๋ชจ์ต์ด๋ค. ์นด์นด์ค ์ฌ์ฉ์์ ๊ณ ์ id, ์ด๋ฆ, ํ๋กํ ์ด๋ฏธ์ง, ์ด๋ฉ์ผ์ด ๋ด๊ฒจ์๋ค. ์ด๋ฆ๊ณผ ํ๋กํ ์ด๋ฏธ์ง๊น์ง๋ ํ์ ๋์์ง๋ง ์ด๋ฉ์ผ์ ๋ก๊ทธ์ธํ ๋ ์ง์ ๋์๋ฅผ ๋๋ฌ์ฃผ์ด์ผ๋ง ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์๋ค.
์นด์นด์ค ์ฌ์ฉ์ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ
onSuccess
์ผ๋ ์คํํ ํจ์๋ ์์ ๊ฐ์ด ์ ์ด์ฃผ์๋ค. ์๋ต ๊ฐ์ฒด์์ ๊ฐ๋ค์ ๊ฐ์ ธ์ context์์ ๊ด๋ฆฌํ๊ณ ์๋ ์ํ์ ์ ์ฅํ๋ค.
ํ ํฐ์ ์ฟ ํค์ ์ ์ฅํ๋ค. ๊ธฐํ์ ์ผ๋จ ์์ฃผ ๋ง์ด. universal-cookie ํจํค์ง๋ฅผ ์ด์ฉํ๋ค.
<KakaoLogin
token={"fa56968f0f3fbbad13f3656328dee767"}
onSuccess={(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}`);
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");
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์ ๊ฐ์ด ๋ค์ด์ค๋ฉด ๋ก๊ทธ์ธ ์ ๋ณด๋ค์ ๋ ๋๋ง ํ๋ค.
์ด๋ ๊ฒ ์นด์นด์ค ๋ก๊ทธ์ธ ๊ธฐ๋ฅ์ ๋ด ์๋ฒ์ ์ด์ฉํ ์ ์๋ค.