diff --git a/components/Auth/SnsLogin.tsx b/components/Auth/SnsLogin.tsx
index 2a4a2a6..f5b1d64 100644
--- a/components/Auth/SnsLogin.tsx
+++ b/components/Auth/SnsLogin.tsx
@@ -6,7 +6,9 @@ const SnsLogin = () => {
소셜 로그인
-
+
=4.0"
}
},
+ "node_modules/jwt-decode": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz",
+ "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/keyv": {
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
diff --git a/package.json b/package.json
index e60463b..eacb036 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
"dependencies": {
"axios": "^1.7.7",
"cookie": "^1.0.1",
+ "jwt-decode": "^4.0.0",
"next": "15.0.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/pages/api/auth/sign-in/google.ts b/pages/api/auth/sign-in/google.ts
new file mode 100644
index 0000000..e68df2c
--- /dev/null
+++ b/pages/api/auth/sign-in/google.ts
@@ -0,0 +1,124 @@
+import axios from "axios";
+import axiosInstance from "@/lib/api/axiosInstanceApi";
+import { NextApiRequest, NextApiResponse } from "next";
+import { serialize } from "cookie";
+import { jwtDecode } from "jwt-decode";
+
+interface GoogleUserInfo {
+ name: string;
+}
+
+const handler = async (req: NextApiRequest, res: NextApiResponse) => {
+ try {
+ const { code } = req.query;
+ if (!code) {
+ return res.status(400).json({ message: "인증 코드가 없습니다." });
+ }
+
+ const clientId = process.env.GOOGLE_CLIENT_ID;
+ const clientSecret = process.env.GOOGLE_CLIENT_SECRET;
+ const redirectUri =
+ process.env.GOOGLE_REDIRECT_URI || "http://localhost:3000/";
+
+ if (!clientId || !clientSecret) {
+ return res
+ .status(500)
+ .json({ message: "Google API 클라이언트 정보가 설정되지 않았습니다." });
+ }
+
+ // 토큰 요청
+ const tokenUrl = "https://oauth2.googleapis.com/token";
+ const params = {
+ code: code as string,
+ client_id: clientId,
+ client_secret: clientSecret,
+ redirect_uri: redirectUri,
+ grant_type: "authorization_code",
+ };
+
+ const tokenResponse = await axios.post(tokenUrl, params);
+ const { id_token } = tokenResponse.data;
+ if (!id_token) {
+ return res
+ .status(401)
+ .json({ message: "ID 토큰을 가져오지 못했습니다." });
+ }
+
+ // Google ID 토큰에서 사용자 정보 추출
+ const userInfo: GoogleUserInfo = jwtDecode(id_token);
+ const { name } = userInfo;
+ console.log(name);
+
+ // 이미 회원인지 체크
+ try {
+ const loginResponse = await axiosInstance.post("/auth/sign-in/google", {
+ token: id_token,
+ redirectUri,
+ });
+
+ const accessToken = loginResponse.data.access_token;
+ if (accessToken) {
+ res.setHeader(
+ "Set-Cookie",
+ serialize("accessToken", accessToken, {
+ httpOnly: true,
+ secure: process.env.NODE_ENV === "production",
+ sameSite: "lax",
+ maxAge: 60 * 60 * 24,
+ path: "/",
+ })
+ );
+ return res.redirect("http://localhost:3000");
+ }
+ } catch (loginError: any) {
+ console.error(
+ "로그인 실패:",
+ loginError.response?.data || loginError.message
+ );
+
+ // 로그인 실패 시 회원가입 시도
+ try {
+ const signUpResponse = await axiosInstance.post(
+ "/auth/sign-up/google",
+ {
+ name: name || "사용자",
+ token: id_token,
+ redirectUri: "http://localhost:3000",
+ }
+ );
+
+ const accessToken = signUpResponse.data.access_token;
+ if (accessToken) {
+ res.setHeader(
+ "Set-Cookie",
+ serialize("accessToken", accessToken, {
+ httpOnly: true,
+ secure: process.env.NODE_ENV === "production",
+ sameSite: "lax",
+ maxAge: 60 * 60 * 24,
+ path: "/",
+ })
+ );
+ return res.redirect("http://localhost:3000");
+ }
+ } catch (signUpError: any) {
+ console.error(
+ "회원가입 실패:",
+ signUpError.response?.data || signUpError.message
+ );
+ return res.status(500).json({
+ message: "회원가입 중 오류가 발생했습니다.",
+ error: signUpError.response?.data || signUpError.message,
+ });
+ }
+ }
+ } catch (error: any) {
+ console.error("Error:", error.response?.data || error.message);
+ return res.status(500).json({
+ message: "서버 오류",
+ error: error.response?.data || error.message,
+ });
+ }
+};
+
+export default handler;
diff --git a/pages/api/auth/sign-in.ts b/pages/api/auth/sign-in/index.ts
similarity index 100%
rename from pages/api/auth/sign-in.ts
rename to pages/api/auth/sign-in/index.ts
diff --git a/pages/api/auth/sign-up.ts b/pages/api/auth/sign-up/index.ts
similarity index 100%
rename from pages/api/auth/sign-up.ts
rename to pages/api/auth/sign-up/index.ts
diff --git a/pages/favorite/index.tsx b/pages/favorite/index.tsx
index c54b44c..662ced2 100644
--- a/pages/favorite/index.tsx
+++ b/pages/favorite/index.tsx
@@ -1,8 +1,9 @@
import { GetServerSideProps, GetServerSidePropsContext } from "next";
-import { proxy } from "@/lib/api/axiosInstanceApi";
+import axiosInstance, { proxy } from "@/lib/api/axiosInstanceApi";
import LinkCard from "@/components/LinkCard";
import CardsLayout from "@/components/Layout/CardsLayout";
import Container from "@/components/Layout/Container";
+import { parse } from "cookie";
interface FavoriteDataType {
id: number;
@@ -24,13 +25,11 @@ export const getServerSideProps: GetServerSideProps = async (
) => {
// 클라이언트의 쿠키 가져오기
const { req } = context;
- const cookies = req.headers.cookie || "";
-
+ const cookies = parse(req.headers.cookie || "");
+ const accessToken = cookies.accessToken;
try {
- const res = await proxy.get("/api/favorites", {
- headers: {
- Cookie: cookies,
- },
+ const res = await axiosInstance.get("/favorites?page=1&pageSize=10", {
+ headers: { Authorization: `Bearer ${accessToken}` },
});
const { list, totalCount } = res.data || { list: [], totalCount: 0 };
diff --git a/pages/google.tsx b/pages/google.tsx
index 9f0059a..25dce71 100644
--- a/pages/google.tsx
+++ b/pages/google.tsx
@@ -1,3 +1,4 @@
+import { proxy } from "@/lib/api/axiosInstanceApi";
import axios from "axios";
import { useEffect } from "react";
@@ -5,17 +6,50 @@ const Google = () => {
useEffect(() => {
const hash = window.location.hash;
const params = new URLSearchParams(hash.substring(1));
- const token = params.get("access_token");
- console.log(token);
+ const idToken = params.get("id_token"); // Google에서 전달받은 id_token
+ const accessToken = params.get("access_token"); // Google에서 전달받은 id_token
- axios
- .get(`https://www.googleapis.com/oauth2/v2/userinfo`, {
- headers: { Authorization: `Bearer ${token}` },
- })
- .then((res) => console.log(res));
+ if (accessToken) {
+ console.log(" Access Token:", accessToken);
+ proxy
+ .post("/api/auth/sign-up/google", {
+ name: "박문균",
+ token: accessToken,
+ redirectUri: "http://localhost:3000/google",
+ })
+ .then((response) => {
+ console.log("Authentication Success:", response.data);
+ // 성공적인 로그인 처리 후, 리다이렉션 등의 작업을 할 수 있습니다.
+ })
+ .catch((error) => {
+ console.error("Authentication Error:", error);
+ });
+ } else {
+ console.error("Access Token이 없습니다.");
+ }
+
+ if (idToken) {
+ console.log("Id Token:", idToken);
+
+ // 서버로 id_token을 전달하여 인증을 요청합니다.
+ proxy
+ .post("/api/auth/sign-in/google", {
+ token: idToken,
+ redirectUri: "http://localhost:3000/google",
+ })
+ .then((response) => {
+ console.log("Authentication Success:", response.data);
+ // 성공적인 로그인 처리 후, 리다이렉션 등의 작업을 할 수 있습니다.
+ })
+ .catch((error) => {
+ console.error("Authentication Error:", error);
+ });
+ } else {
+ console.error("Id Token이 없습니다.");
+ }
}, []);
- return 안녕
;
+ return Google OAuth 로그인 완료
;
};
export default Google;