From 112a99f896736006c7bcf9b0d4a369ab5fa3070c Mon Sep 17 00:00:00 2001 From: NARARIA03 Date: Sun, 8 Sep 2024 00:38:48 +0900 Subject: [PATCH 1/2] =?UTF-8?q?Chore:=20Axios=EA=B0=80=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=EB=90=9C=20=EC=BD=94=EB=93=9C=EB=93=A4=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=20=EC=84=A0=EC=96=B8=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit try - catch를 사용하고, response와 error에 제네릭 문법과 isAxiosError를 사용해서 타입을 적용해주었다. --- src/routers/kakaoRouter.ts | 17 +++--- src/types/kakao_login/kakaoLoginType.ts | 9 +++ src/utils/kakao.ts | 81 ++++++++++++++----------- 3 files changed, 65 insertions(+), 42 deletions(-) diff --git a/src/routers/kakaoRouter.ts b/src/routers/kakaoRouter.ts index 000c8ba..56f1c24 100644 --- a/src/routers/kakaoRouter.ts +++ b/src/routers/kakaoRouter.ts @@ -1,6 +1,5 @@ import { Router, Request, Response } from "express"; import { KakaoClient } from "../utils/kakao"; -import { KakaoTokenData } from "../types/kakao_login/kakaoLoginType"; import handleLogin from "../utils/handleLogin"; const router = Router(); @@ -24,13 +23,15 @@ router.post("/login", async (req: Request, res: Response) => { console.log("POST /kakao/login start"); try { const { code }: { code: string } = req.body; - const kakaoToken: KakaoTokenData = await KakaoClient.getKakaoToken(code); - const userData = await KakaoClient.getUserData(kakaoToken); - - console.log("최종적으로 사용할 userData: ", userData); - - const dataWithJWT = await handleLogin(userData); - res.status(200).json(dataWithJWT); + const kakaoToken = await KakaoClient.getKakaoToken(code); + if (kakaoToken) { + const userData = await KakaoClient.getUserData(kakaoToken); + if (userData) { + console.log("최종적으로 사용할 userData: ", userData); + const dataWithJWT = await handleLogin(userData); + res.status(200).json(dataWithJWT); + } + } } catch (err) { console.error("POST /kakao/login Error: ", err); } diff --git a/src/types/kakao_login/kakaoLoginType.ts b/src/types/kakao_login/kakaoLoginType.ts index 1cef15f..6b07b83 100644 --- a/src/types/kakao_login/kakaoLoginType.ts +++ b/src/types/kakao_login/kakaoLoginType.ts @@ -13,6 +13,15 @@ export type KakaoTokenData = { refresh_token: string; }; +export type KakaoUserData = { + id: string; + kakao_account: { + profile: { + nickname: string; + }; + }; +}; + export type UserData = { id: string; nickname: string; diff --git a/src/utils/kakao.ts b/src/utils/kakao.ts index c7ebf7c..81bac20 100644 --- a/src/utils/kakao.ts +++ b/src/utils/kakao.ts @@ -1,9 +1,9 @@ -import axios from "axios"; +import axios, { isAxiosError } from "axios"; import dotenv from "dotenv"; import { KakaoResult, KakaoTokenData, - UserData, + KakaoUserData, } from "../types/kakao_login/kakaoLoginType"; dotenv.config(); @@ -42,44 +42,57 @@ class Kakao { redirect_uri: this.redirectUri, }; - const data: KakaoResult = await axios - .post("https://kauth.kakao.com/oauth/token", params, { - headers: { - "Content-Type": "application/x-www-form-urlencoded", - }, - }) - .then((data) => data.data) - .catch((err) => console.error("getKakaoToken function Error: ", err)); - - const tokenData: KakaoTokenData = { - access_token: data.access_token, - refresh_token: data.refresh_token, - }; - // console.log("kakaoTokenData: ", tokenData); - - return tokenData; + try { + const data = await axios.post( + "https://kauth.kakao.com/oauth/token", + params, + { + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + } + ); + if (data.data) { + const tokenData: KakaoTokenData = { + access_token: data.data.access_token, + refresh_token: data.data.refresh_token, + }; + return tokenData; + } + } catch (err) { + if (isAxiosError(err)) { + console.error( + `getKakaoToken func Error: ${err.status}, ${err.response?.data}` + ); + } + } } /** * @description 받아온 kakaoToken의 access_token을 사용해 userData를 받아오는 함수 */ async getUserData(token: KakaoTokenData) { - const data = await axios - .get("https://kapi.kakao.com/v2/user/me", { - headers: { - Authorization: `Bearer ${token.access_token}`, - }, - }) - .then((data) => data.data) - .catch((err) => console.error("getUserData function Error: ", err)); - // console.log("raw user data: ", data); - - const userData: UserData = { - id: data.id, - nickname: data.kakao_account.profile.nickname, - }; - - return userData; + try { + const response = await axios.get( + "https://kapi.kakao.com/v2/user/me", + { + headers: { + Authorization: `Bearer ${token.access_token}`, + }, + } + ); + const userData = { + id: response.data.id, + nickname: response.data.kakao_account.profile.nickname, + }; + return userData; + } catch (err) { + if (isAxiosError(err)) { + console.error( + `getUserData function Error: ${err.status}, ${err.response?.data} ` + ); + } + } } } From 313b7d22c0f2919b97e3896cc0ee4324a5306651 Mon Sep 17 00:00:00 2001 From: NARARIA03 Date: Sun, 8 Sep 2024 02:44:49 +0900 Subject: [PATCH 2/2] =?UTF-8?q?Chore:=20router=EC=97=90=20log=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=ED=95=B4=20=EB=8F=99=EC=9E=91=20=ED=8C=8C=EC=95=85?= =?UTF-8?q?=EC=9D=B4=20=EC=89=BD=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 어떤 router가 어떤 상태코드로 어떤걸 반환하는지를 console.log로 함께 작 성해서 터미널로도 로그인 / 토큰 검증 로직이 어떻게 동작 중인지 파악하기 쉽도록 해주었다. --- src/routers/kakaoRouter.ts | 4 +--- src/routers/tokenRouter.ts | 13 +++++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/routers/kakaoRouter.ts b/src/routers/kakaoRouter.ts index 56f1c24..6e5cbe4 100644 --- a/src/routers/kakaoRouter.ts +++ b/src/routers/kakaoRouter.ts @@ -5,7 +5,6 @@ import handleLogin from "../utils/handleLogin"; const router = Router(); router.get("/url", (req: Request, res: Response) => { - console.log("GET /kakao/url start"); try { const url = KakaoClient.getAuthCodeUrl(); res.status(200).json({ @@ -20,14 +19,13 @@ router.get("/url", (req: Request, res: Response) => { }); router.post("/login", async (req: Request, res: Response) => { - console.log("POST /kakao/login start"); try { const { code }: { code: string } = req.body; const kakaoToken = await KakaoClient.getKakaoToken(code); if (kakaoToken) { const userData = await KakaoClient.getUserData(kakaoToken); if (userData) { - console.log("최종적으로 사용할 userData: ", userData); + console.log("POST /kakao/login success"); const dataWithJWT = await handleLogin(userData); res.status(200).json(dataWithJWT); } diff --git a/src/routers/tokenRouter.ts b/src/routers/tokenRouter.ts index f8ff360..2f914a9 100644 --- a/src/routers/tokenRouter.ts +++ b/src/routers/tokenRouter.ts @@ -11,6 +11,9 @@ const router = Router(); // 이를 위해 token 검증을 수행하는 엔드포인트다. router.get("/validate", (req: Request, res: Response) => { if (!req.headers.authorization) { + console.log( + "GET /token/validate 400: authorization 헤더에 jwt가 담겨있지 않습니다" + ); res.status(400).json({ ok: false, message: "authorization 헤더에 jwt가 담겨있지 않습니다", @@ -19,12 +22,14 @@ router.get("/validate", (req: Request, res: Response) => { } const accessToken = req.headers.authorization.split(" ")[1]; if (verifyAccessToken(accessToken)) { + console.log("GET /token/validate 200: accessToken이 만료되지 않았습니다"); res.status(200).json({ ok: true, message: "accessToken이 만료되지 않았습니다", }); return; } else { + console.log("GET /token/validate 401: accessToken이 만료되었습니다"); res.status(401).json({ ok: false, message: "accessToken이 만료되었습니다", @@ -48,12 +53,16 @@ router.get("/refresh", async (req: Request, res: Response) => { if (isVerifyRefreshToken) { // accessToken은 만료되었지만, refreshToken은 만료되지 않은 경우 const newAccessToken = generateAccessToken(decoded.id); + console.log("GET /token/refresh 200: 새 accessToken을 발급했습니다"); res.status(200).json({ accessToken: newAccessToken, }); } else { // 둘 다 만료된 경우 // FE쪽 로그아웃 시켜야 함 + console.log( + "GET /token/refresh 401: accessToken, refreshToken 모두 만료되었습니다" + ); res.status(401).json({ ok: false, message: "Both tokens expired", @@ -61,6 +70,7 @@ router.get("/refresh", async (req: Request, res: Response) => { } } else { // accessToken을 디코딩 한 결과가 비어있는 경우 + console.log("GET /token/refresh 400: accessToken에 문제가 있습니다"); res.status(400).json({ ok: false, message: "No Authorized", @@ -68,6 +78,9 @@ router.get("/refresh", async (req: Request, res: Response) => { } } else { // refreshToken과 accessToken 모두 존재하지 않는 경우 + console.log( + "GET /token/refresh 400: accessToken과 refreshToken이 요청 headers에 존재하지 않습니다" + ); res.status(400).json({ ok: false, message: "Access token and refresh token not found",