diff --git a/package.json b/package.json index d5434adf03fe4282124d1dcaf9883b12b1e8151c..fd8e5e1a737e66d93bda03124bfed7b098db95d8 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "ws": "^8.18.0" }, "scripts": { - "start": "HTTPS=true react-scripts start", + "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" diff --git a/src/App.js b/src/App.js index 4bf82aaa414a233195f7efabc321fe1e75a7c343..0dd250e25c1216cfbf912f0c13ede69396ae6667 100644 --- a/src/App.js +++ b/src/App.js @@ -1,11 +1,11 @@ -import React, { useState, useEffect, createContext, useContext } from 'react'; +import React, { useState, createContext, useContext } from 'react'; import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom'; import { ToastContainer, toast } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; -import axios from 'axios'; import Home from './pages/Home'; import Login from './pages/Login'; import MyPage from './pages/MyPage'; +import jwt_decode from 'jwt-decode'; import './App.css'; const AuthContext = createContext(); @@ -19,78 +19,57 @@ export function useToast() { return useContext(ToastContext); } +// function App() { +// const [isAuthenticated, setIsAuthenticated] = useState(false); +// const [user, setUser] = useState(null); -function App() { - const [isAuthenticated, setIsAuthenticated] = useState(false); - const [user, setUser] = useState(null); +// const login = (userData) => { +// setUser(userData); +// setIsAuthenticated(true); +// }; - useEffect(() => { - const checkAuthStatus = async () => { - try { - // 서버가 실행 중인지 먼저 확인 - const response = await axios.get('https://localhost:8000/auth/status', { - withCredentials: true, - headers: { - 'Content-Type': 'application/json', - 'Authorization': localStorage.getItem('token') // 토큰이 있다면 함께 전송 - }, - timeout: 5000 // 5초 타임아웃 설정 - }); - - if (response.status === 200) { - setUser(response.data.user); - setIsAuthenticated(true); - } - } catch (error) { - console.error('인증 상태 확인 오류:', error); - if (error.code === 'ERR_NETWORK') { - console.log('서버 연결에 실패했습니다. 서버가 실행중인지 확인해주세요.'); - } else if (error.response?.status === 401) { - console.log('인증되지 않은 사용자입니다.'); - } - setIsAuthenticated(false); - setUser(null); - } - }; +// //jwt 전 로그인------------------------- +// // const logout = () => { +// // setUser(null); +// // setIsAuthenticated(false); +// // }; +// //jwt 전 로그인------------------------- - checkAuthStatus(); - }, []); // 의존성 배열을 비워서 마운트 시에만 실행 +// //jwt 후 로그인------------------------- +// const logout = () => { +// localStorage.removeItem('token'); +// delete axios.defaults.headers.common['Authorization']; +// setUser(null); +// setIsAuthenticated(false); +// }; +//jwt 후 로그인------------------------- +function App() { + const [isAuthenticated, setIsAuthenticated] = useState(() => { + const token = localStorage.getItem('token'); + return !!token; + }); + const [user, setUser] = useState(() => { + const token = localStorage.getItem('token'); + if (token) { + const decoded = jwt_decode(token); + return { + _id: decoded.userId, + email: decoded.email, + name: decoded.name + }; + } + return null; + }); const login = (userData) => { setUser(userData); setIsAuthenticated(true); }; - const logout = async () => { + const logout = () => { + localStorage.removeItem('token'); setUser(null); setIsAuthenticated(false); - toast.success('로그아웃되었습니다.'); - // try { - // // 로그아웃 요청 전에 현재 상태 초기화 - // setUser(null); - // setIsAuthenticated(false); - - // // 로그아웃 요청 시도 - // await axios.get('https://localhost:8000/logout', { - // withCredentials: true, - // headers: { - // 'Content-Type': 'application/json' - // } - // }); - - // toast.success('로그아웃되었습니다.'); - - // } catch (error) { - // console.error('로그아웃 오류:', error); - - // if (error.code === 'ERR_NETWORK') { - // toast.error('서버와의 연결이 끊어졌습니다. 네트워크 연결을 확인해주세요.'); - // } else if (error.response?.status === 403) { - // toast.error('접근이 거부되었습니다. CORS 설정을 확인해주세요.'); - // } else { - // toast.error('로그아웃 처리 중 오류가 발생했습니다.'); - // } - // } }; return ( @@ -109,9 +88,15 @@ function App() { ); } +// function PrivateRoute({ children }) { +// const { isAuthenticated } = useAuth(); +// return isAuthenticated ? children : <Navigate to="/login" />; +// } + function PrivateRoute({ children }) { const { isAuthenticated } = useAuth(); - return isAuthenticated ? children : <Navigate to="/login" />; + const token = localStorage.getItem('token'); + return isAuthenticated && token ? children : <Navigate to="/login" />; } export default App; diff --git a/src/api/api.js b/src/api/api.js index a2dee60d594c6ce3cda414b4f70fc6e199cad262..61f6f01aa40be493c6cfb214d330d86b9935670b 100644 --- a/src/api/api.js +++ b/src/api/api.js @@ -2,40 +2,18 @@ import axios from 'axios'; const api = axios.create({ - baseURL: 'https://localhost:8000', - withCredentials: true, //쿠키전송 허용 + baseURL: 'http://localhost:8000', }); -// api.interceptors.request.use( -// (config) => { -// const token = localStorage.getItem('token'); -// if (token) { -// config.headers['Authorization'] = `Bearer ${token}`; -// } -// return config; -// }, -// (error) => Promise.reject(error) -// ); - -api.interceptors.response.use( - response => response, - async error => { - const originalRequest = error.config; - if ((error.response.status === 401 || error.response.status === 403) && !originalRequest._retry) { - originalRequest._retry = true; - try { - await api.post('/token'); // 토큰 재발급 요청 - return api(originalRequest); // 원래 요청 재시도 - } catch (err) { - // 재발급 실패 시 로그아웃 처리 등 추가 로직 구현 - // 예를 들어, 사용자에게 재로그인을 요청하거나 로그아웃 처리 - window.location.href = '/login'; - return Promise.reject(error); - } - } - return Promise.reject(error); +api.interceptors.request.use( + (config) => { + const token = localStorage.getItem('token'); + if (token) { + config.headers['Authorization'] = `Bearer ${token}`; } + return config; + }, + (error) => Promise.reject(error) ); - export default api; diff --git a/src/pages/Home.js b/src/pages/Home.js index 79ecf38c58f19cb778b45fc16642da224620162a..00fd7fc5a2f2e5c21101d99a2324c5fc50623b6e 100644 --- a/src/pages/Home.js +++ b/src/pages/Home.js @@ -57,7 +57,7 @@ const Home = () => { }, [trips, ws]); useEffect(() => { - const websocket = new WebSocket('ws://localhost:8000'); + const websocket = new WebSocket(`ws://${window.location.hostname}:8000`); websocket.onopen = () => { console.log('WebSocket 연결됨'); diff --git a/src/pages/Login.js b/src/pages/Login.js index eecefe61b9bb3a630375a6456d1099dd0d0c3986..c92837ae556c84623e179bc2df3016f70c6504db 100644 --- a/src/pages/Login.js +++ b/src/pages/Login.js @@ -12,9 +12,52 @@ function Login() { const [loading, setLoading] = useState(false); const [isSignUp, setIsSignUp] = useState(false); const navigate = useNavigate(); - const { login, isAuthenticated, user } = useAuth(); + const { login } = useAuth(); const toast = useToast(); + + //jwt 전 로그인------------------------- + // useEffect(() => { + // const params = new URLSearchParams(window.location.search); + // const userParam = params.get('user'); + + // if (userParam) { + // try { + // const userData = JSON.parse(decodeURIComponent(userParam)); + // login(userData); + // toast.success('구글 로그인에 성공했습니다.'); + // navigate('/'); + // } catch (error) { + // console.error('구글 로그인 처리 중 오류 발생:', error); + // toast.error('구글 로그인 중 오류가 발생했습니다.'); + // } + // } + // }, [navigate, login, toast]); + //jwt 전 로그인------------------------- + //jwt 후 로그인------------------------- + useEffect(() => { + const params = new URLSearchParams(window.location.hash.substring(1)); + const tokenParam = params.get('token'); + + if (tokenParam) { + // 토큰 저장 + localStorage.setItem('token', tokenParam); + + // 토큰에서 사용자 정보 추출 + const decoded = jwt_decode(tokenParam); + const userData = { + _id: decoded.userId, + email: decoded.email, + name: decoded.name + }; + + login(userData); + + toast.success('구글 로그인에 성공했습니다.'); + navigate('/'); + } + }, [navigate, login, toast]); + //jwt 후 로그인------------------------- //jwt 전 로그인------------------------- @@ -49,30 +92,6 @@ function Login() { //jwt 전 로그인------------------------- //jwt 후 로그인------------------------- - //secure 추가 - // 구글 로그인 후 인증 상태 확인 함수 - const handleGoogleLoginCallback = async () => { - try { - // 인증 상태 확인 - const response = await axios.get('https://localhost:8000/auth/status', { withCredentials: true }); - if (response.status === 200) { - login(response.data.user); - toast.success('구글 로그인에 성공했습니다.'); - navigate('/'); - } else { - toast.error('구글 로그인에 실패했습니다.'); - } - } catch (error) { - console.error('Authentication status error:', error); - toast.error('구글 로그인 중 오류가 발생했습니다.'); - } - }; - - useEffect(() => { - if(isAuthenticated){ - handleGoogleLoginCallback(); - } - }, [isAuthenticated, user]); // isAuthenticated나 user가 변경될 때만 실행 // handleLogin 함수만 수정 const handleLogin = async (e) => { e.preventDefault(); @@ -95,22 +114,21 @@ const handleLogin = async (e) => { // toast.success('로그인에 성공했습니다.'); // navigate('/'); // } - const response = await axios.post('https://localhost:8000/login', { + const response = await axios.post('http://localhost:8000/login', { email: username, password: password - }, {withCredentials: true}); //쿠키 전송 허용 + }); if (response.status === 200) { - // const token = response.data.token; - // localStorage.setItem('token', token); + const token = response.data.token; + localStorage.setItem('token', token); - // const decoded = jwt_decode(token); - // const userData = { - // _id: decoded.userId, - // email: decoded.email, - // name: decoded.name - // }; - const userData = response.data.user; + const decoded = jwt_decode(token); + const userData = { + _id: decoded.userId, + email: decoded.email, + name: decoded.name + }; login(userData); toast.success('로그인에 성공했습니다.'); @@ -130,7 +148,7 @@ const handleLogin = async (e) => { //jwt 후 로그인------------------------- const handleGoogleLogin = () => { - window.location.href = 'https://localhost:8000/googlelogin'; + window.location.href = 'http://localhost:8000/googlelogin'; }; const handleSignUp = async (e) => { @@ -138,7 +156,7 @@ const handleLogin = async (e) => { setLoading(true); try { - const response = await axios.post('https://localhost:8000/signup', { + const response = await axios.post('http://localhost:8000/signup', { email: username, password: password, name: name @@ -146,7 +164,7 @@ const handleLogin = async (e) => { if (response.status === 201) { toast.success('회원가입에 성공했습니다.'); - const loginResponse = await axios.post('https://localhost:8000/login', { + const loginResponse = await axios.post('http://localhost:8000/login', { email: username, password: password }); @@ -211,7 +229,7 @@ const handleLogin = async (e) => { </button> </form> <button className="google-button" onClick={handleGoogleLogin} disabled={loading}> - <svg className="google-icon" viewBox="-3 0 262 262" xmlns="https://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid" fill="#000000"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"><path d="M255.878 133.451c0-10.734-.871-18.567-2.756-26.69H130.55v48.448h71.947c-1.45 12.04-9.283 30.172-26.69 42.356l-.244 1.622 38.755 30.023 2.685.268c24.659-22.774 38.875-56.282 38.875-96.027" fill="#4285F4"></path><path d="M130.55 261.1c35.248 0 64.839-11.605 86.453-31.622l-41.196-31.913c-11.024 7.688-25.82 13.055-45.257 13.055-34.523 0-63.824-22.773-74.269-54.25l-1.531.13-40.298 31.187-.527 1.465C35.393 231.798 79.49 261.1 130.55 261.1" fill="#34A853"></path><path d="M56.281 156.37c-2.756-8.123-4.351-16.827-4.351-25.82 0-8.994 1.595-17.697 4.206-25.82l-.073-1.73L15.26 71.312l-1.335.635C5.077 89.644 0 109.517 0 130.55s5.077 40.905 13.925 58.602l42.356-32.782" fill="#FBBC05"></path><path d="M130.55 50.479c24.514 0 41.05 10.589 50.479 19.438l36.844-35.974C195.245 12.91 165.798 0 130.55 0 79.49 0 35.393 29.301 13.925 71.947l42.211 32.783c10.59-31.477 39.891-54.251 74.414-54.251" fill="#EB4335"></path></g></svg> + <svg className="google-icon" viewBox="-3 0 262 262" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid" fill="#000000"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"><path d="M255.878 133.451c0-10.734-.871-18.567-2.756-26.69H130.55v48.448h71.947c-1.45 12.04-9.283 30.172-26.69 42.356l-.244 1.622 38.755 30.023 2.685.268c24.659-22.774 38.875-56.282 38.875-96.027" fill="#4285F4"></path><path d="M130.55 261.1c35.248 0 64.839-11.605 86.453-31.622l-41.196-31.913c-11.024 7.688-25.82 13.055-45.257 13.055-34.523 0-63.824-22.773-74.269-54.25l-1.531.13-40.298 31.187-.527 1.465C35.393 231.798 79.49 261.1 130.55 261.1" fill="#34A853"></path><path d="M56.281 156.37c-2.756-8.123-4.351-16.827-4.351-25.82 0-8.994 1.595-17.697 4.206-25.82l-.073-1.73L15.26 71.312l-1.335.635C5.077 89.644 0 109.517 0 130.55s5.077 40.905 13.925 58.602l42.356-32.782" fill="#FBBC05"></path><path d="M130.55 50.479c24.514 0 41.05 10.589 50.479 19.438l36.844-35.974C195.245 12.91 165.798 0 130.55 0 79.49 0 35.393 29.301 13.925 71.947l42.211 32.783c10.59-31.477 39.891-54.251 74.414-54.251" fill="#EB4335"></path></g></svg> Sign in with Google </button> <button