KIM-JINO5 2 kuukautta sitten
vanhempi
sitoutus
334bce0ca3

+ 5 - 4
app/(auth)/layout.tsx

@@ -3,7 +3,7 @@
 import "./style.scss";
 import Image from 'next/image';
 import Link from 'next/link';
-import { useRouter } from 'next/navigation';
+import { useRouter, usePathname } from 'next/navigation';
 import { useEffect } from 'react';
 import { GoogleOAuthProvider } from '@react-oauth/google';
 import useAuth from '@/hooks/useAuth';
@@ -11,15 +11,16 @@ import { useConfigContext } from '@/contexts/configProvider';
 
 export default function Layout({ children }: { children: React.ReactNode }) {
     const router = useRouter();
+    const pathname = usePathname();
     const { isAuthenticated, isLoading } = useAuth();
     const config = useConfigContext();
 
-    // 이미 로그인된 상태면 홈으로 리다이렉트
+    // 이미 로그인된 상태면 홈으로 리다이렉트 (Google 로그인 완료 페이지 제외)
     useEffect(() => {
-        if (!isLoading && isAuthenticated) {
+        if (!isLoading && isAuthenticated && !pathname.startsWith('/login/google/complete')) {
             router.replace('/');
         }
-    }, [isAuthenticated, isLoading, router]);
+    }, [isAuthenticated, isLoading, router, pathname]);
 
     return (
         <div className="grid grid-rows-[1fr_20px] items-center justify-items-center min-h-screen p-4 sm:p-20 font-[family-name:var(--font-geist-sans)]">

+ 13 - 9
app/auth/login/google/callback/route.ts → app/(auth)/login/google/callback/route.ts

@@ -1,7 +1,7 @@
 import { NextRequest, NextResponse } from 'next/server';
-import { ResultDto } from '@/types/response/common';
 import { LoginResponse } from '@/types/response/auth';
-import { fetchJson } from '@/lib/utils/server';
+
+const API_URL = process.env.API_URL;
 
 export async function POST(request: NextRequest)
 {
@@ -15,15 +15,19 @@ export async function POST(request: NextRequest)
 		return NextResponse.redirect(url);
 	}
 
-	// 백엔드 google-login API 호출
-	const res: ResultDto = await fetchJson('/api/auth/google-login', {
+	// 백엔드 google-login API 직접 호출
+	const res = await fetch(`${API_URL}/api/auth/google-login`, {
 		method: 'POST',
-		body: JSON.stringify({ credential })
+		headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
+		body: JSON.stringify({ credential }),
+		cache: 'no-store'
 	});
 
-	if (res.success && res.data) {
-		const data = res.data as LoginResponse;
-		const response = NextResponse.redirect(new URL('/auth/login/google/complete', request.url));
+	const json = await res.json();
+
+	if (json.success && json.data) {
+		const data = json.data as LoginResponse;
+		const response = NextResponse.redirect(new URL('/login/google/complete', request.url));
 		const cookieOptions = { httpOnly: true, path: '/' };
 		response.cookies.set('accessToken', data.accessToken, cookieOptions);
 		response.cookies.set('refreshToken', data.refreshToken, cookieOptions);
@@ -32,6 +36,6 @@ export async function POST(request: NextRequest)
 
 	// 실패 시 로그인 페이지로 리다이렉트
 	const url = new URL('/login', request.url);
-	url.searchParams.set('error', res.message || 'Google 로그인에 실패했습니다.');
+	url.searchParams.set('error', json.message || 'Google 로그인에 실패했습니다.');
 	return NextResponse.redirect(url);
 }

+ 5 - 0
app/(auth)/login/google/complete/loading.tsx

@@ -0,0 +1,5 @@
+import LoadHtml from '@/app/component/Loading';
+
+export default function Loading() {
+	return <LoadHtml />;
+}

+ 22 - 0
app/(auth)/login/google/complete/page.tsx

@@ -0,0 +1,22 @@
+'use client';
+
+import { useEffect } from 'react';
+import Image from 'next/image';
+import useAuth from '@/hooks/useAuth';
+
+export default function Page()
+{
+	const { login } = useAuth();
+
+	useEffect(() => {
+		login(true);
+	}, []);
+
+	return (
+		<div className="fixed inset-0 flex flex-col items-center justify-center gap-6 bg-[var(--bg-page)] z-50">
+			<Image src="/resources/m-logo.png" alt="bitforum" width={256} height={64} className="w-36 sm:w-44 h-auto" priority />
+			<div className="w-7 h-7 border-[3px] border-gray-200 border-t-[#F7931A] rounded-full animate-spin" />
+			<p className="text-sm text-[var(--text-muted)]">Google 로그인 처리 중...</p>
+		</div>
+	);
+}

+ 1 - 1
app/(auth)/login/page.tsx

@@ -122,7 +122,7 @@ export default function Page()
                                     shape="rectangular"
                                     context="signin"
                                     ux_mode="redirect"
-                                    login_uri={`${window.location.origin}/auth/login/google/callback`}
+                                    login_uri={`${window.location.origin}/login/google/callback`}
                                     logo_alignment="center"
                                 />
                             )}

+ 0 - 19
app/auth/login/google/complete/page.tsx

@@ -1,19 +0,0 @@
-'use client';
-
-import { useEffect } from 'react';
-import useAuth from '@/hooks/useAuth';
-
-export default function Page()
-{
-	const { login } = useAuth();
-
-	useEffect(() => {
-		login(true);
-	}, []);
-
-	return (
-		<div className="flex items-center justify-center min-h-screen">
-			<p>Google 로그인 처리 중...</p>
-		</div>
-	);
-}

+ 1 - 1
middleware.ts

@@ -24,7 +24,7 @@ export default function middleware(req: NextRequest)
 	const isLoggedIn = !!accessToken && isTokenValid(accessToken);
 
 	const publicRoutes = ['/', '/login', '/register', '/forgot-password', '/reset-password', '/welcome'];
-	if (publicRoutes.includes(pathname)) {
+	if (publicRoutes.includes(pathname) || pathname.startsWith('/login/google/')) {
 		if (isLoggedIn && publicRoutes.filter(r => r !== '/').includes(pathname)) {
 			return NextResponse.redirect(new URL('/', req.url)); // 로그인 상태에서 접근 불가
 		}