diff --git a/src/app/components/ImgInputForm.tsx b/src/app/components/ImgInputForm.tsx index 449b74e..4a27624 100644 --- a/src/app/components/ImgInputForm.tsx +++ b/src/app/components/ImgInputForm.tsx @@ -1,6 +1,6 @@ "use client" -import { useCallback, useRef, useState } from 'react' +import { useCallback, useRef, useState, useEffect } from 'react' import styles from './ImgInputForm.module.css' const MAX_FILE_SIZE = 5 * 1024 * 1024 // 5MB @@ -18,6 +18,24 @@ const ImgInputForm = () => { //process.env.NEXT_PUBLIC_API_URL || const API_BASE = 'http://localhost:9001' + useEffect(() => { + const checkAuth = async () => { + try { + const res = await fetch(`${API_BASE}/auth/check-token`, { + method: 'GET', + credentials: 'include', + }) + if (!res.ok) throw new Error('인증 실패') + console.log('사용자 인증 성공') + } catch (err) { + console.error('사용자 인증 실패:', (err as Error).message) + setError('로그인이 필요합니다.') + } + } + + checkAuth() + }, []) + const handleFile = useCallback((file: File) => { setError(null) setSuccess(null) diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx index de589d7..e3c0fdd 100644 --- a/src/app/login/page.tsx +++ b/src/app/login/page.tsx @@ -1,5 +1,14 @@ 'use client'; -import LoginForm from "../components/LoginForm"; +import LoginForm from '../components/LoginForm'; - \ No newline at end of file +const LoginPage = () => { + return ( +
+

로그인

+ +
+ ); +}; + +export default LoginPage; \ No newline at end of file diff --git a/src/app/pages/oauth/callback.tsx b/src/app/pages/oauth/callback.tsx new file mode 100644 index 0000000..d72731f --- /dev/null +++ b/src/app/pages/oauth/callback.tsx @@ -0,0 +1,51 @@ +'use client'; + +import { useEffect, useState } from 'react'; +import { useRouter } from 'next/navigation'; + +const OAuthCallback = () => { + const router = useRouter(); + const [error, setError] = useState(null); + const [message, setMessage] = useState(null); + + useEffect(() => { + const handleOAuthCallback = async () => { + console.log('OAuth 콜백 처리 중...'); + const urlParams = new URLSearchParams(window.location.search); + const code = urlParams.get('code'); + const error = urlParams.get('error'); + + if (error) { + setError('카카오 로그인 중 오류가 발생했습니다.'); + return; + } + + if (code) { + try { + const res = await fetch('/api/oauth/kakao', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ code }), + }); + + if (!res.ok) throw new Error('서버 요청 실패'); + const data = await res.json(); + setMessage(`로그인 성공: ${data.message}`); + } catch (err) { + setError((err as Error).message || '로그인 처리 중 오류가 발생했습니다.'); + } + } + }; + + handleOAuthCallback(); + }, []); + + return ( +
+ {error &&

{error}

} + {message &&

{message}

} +
+ ); +}; + +export default OAuthCallback; diff --git a/src/pages/api/oauth/kakao.ts b/src/pages/api/oauth/kakao.ts new file mode 100644 index 0000000..74aaaaa --- /dev/null +++ b/src/pages/api/oauth/kakao.ts @@ -0,0 +1,33 @@ +import type { NextApiRequest, NextApiResponse } from 'next'; + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + if (req.method !== 'POST') { + return res.status(405).json({ message: 'Method Not Allowed' }); + } + + const { code } = req.body; + + if (!code) { + return res.status(400).json({ message: 'Authorization code is missing' }); + } + + try { + const tokenResponse = await fetch('https://kauth.kakao.com/oauth/token', { + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body: new URLSearchParams({ + grant_type: 'authorization_code', + client_id: process.env.KAKAO_CLIENT_ID!, + redirect_uri: process.env.KAKAO_REDIRECT_URI!, + code, + }), + }); + + if (!tokenResponse.ok) throw new Error('Failed to fetch access token'); + const tokenData = await tokenResponse.json(); + + res.status(200).json({ message: '카카오 로그인 성공', token: tokenData }); + } catch (err) { + res.status(500).json({ message: (err as Error).message }); + } +}