feat: JWT 만료/로그아웃 시 자동 리다이렉트 처리
All checks were successful
Client CI/CD / deploy (push) Successful in 11s
All checks were successful
Client CI/CD / deploy (push) Successful in 11s
- 401 응답 시 auth:unauthorized 이벤트 발생 (client.js) - AuthContext에서 이벤트 수신 시 자동 로그아웃 - 관리자 페이지에서 인증 만료 시 메인으로, 그 외는 로그인 페이지로 이동 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
26
src/App.jsx
26
src/App.jsx
@@ -1,10 +1,31 @@
|
|||||||
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
|
import { BrowserRouter, Routes, Route, Navigate, useNavigate, useLocation } from 'react-router-dom';
|
||||||
|
import { useEffect, useRef } from 'react';
|
||||||
import { AuthProvider, useAuth } from './context/AuthContext';
|
import { AuthProvider, useAuth } from './context/AuthContext';
|
||||||
import LoginPage from './pages/LoginPage';
|
import LoginPage from './pages/LoginPage';
|
||||||
import RegisterPage from './pages/RegisterPage';
|
import RegisterPage from './pages/RegisterPage';
|
||||||
import HomePage from './pages/HomePage';
|
import HomePage from './pages/HomePage';
|
||||||
import AdminPage from './pages/AdminPage';
|
import AdminPage from './pages/AdminPage';
|
||||||
|
|
||||||
|
function AuthRedirect() {
|
||||||
|
const { user } = useAuth();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const location = useLocation();
|
||||||
|
const prevUserRef = useRef(user);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (prevUserRef.current && !user) {
|
||||||
|
if (location.pathname.startsWith('/admin')) {
|
||||||
|
navigate('/', { replace: true });
|
||||||
|
} else {
|
||||||
|
navigate('/login', { replace: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prevUserRef.current = user;
|
||||||
|
}, [user, navigate, location.pathname]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
function AdminRoute({ children }) {
|
function AdminRoute({ children }) {
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
if (!user) return <Navigate to="/login" replace />;
|
if (!user) return <Navigate to="/login" replace />;
|
||||||
@@ -15,6 +36,8 @@ function AdminRoute({ children }) {
|
|||||||
function AppRoutes() {
|
function AppRoutes() {
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<AuthRedirect />
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/login" element={user ? <Navigate to="/" replace /> : <LoginPage />} />
|
<Route path="/login" element={user ? <Navigate to="/" replace /> : <LoginPage />} />
|
||||||
<Route path="/register" element={user ? <Navigate to="/" replace /> : <RegisterPage />} />
|
<Route path="/register" element={user ? <Navigate to="/" replace /> : <RegisterPage />} />
|
||||||
@@ -28,6 +51,7 @@ function AppRoutes() {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Routes>
|
</Routes>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ export async function apiFetch(path, options = {}) {
|
|||||||
if (token) headers['Authorization'] = `Bearer ${token}`;
|
if (token) headers['Authorization'] = `Bearer ${token}`;
|
||||||
|
|
||||||
const res = await fetch(BASE + path, { ...options, headers });
|
const res = await fetch(BASE + path, { ...options, headers });
|
||||||
|
if (res.status === 401) {
|
||||||
|
window.dispatchEvent(new Event('auth:unauthorized'));
|
||||||
|
}
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const err = new Error(res.statusText);
|
const err = new Error(res.statusText);
|
||||||
err.status = res.status;
|
err.status = res.status;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { createContext, useContext, useState, useCallback } from 'react';
|
import { createContext, useContext, useState, useCallback, useEffect } from 'react';
|
||||||
import { login as apiLogin } from '../api/auth';
|
import { login as apiLogin } from '../api/auth';
|
||||||
|
|
||||||
const AuthContext = createContext(null);
|
const AuthContext = createContext(null);
|
||||||
@@ -26,6 +26,11 @@ export function AuthProvider({ children }) {
|
|||||||
setUser(null);
|
setUser(null);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.addEventListener('auth:unauthorized', logout);
|
||||||
|
return () => window.removeEventListener('auth:unauthorized', logout);
|
||||||
|
}, [logout]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AuthContext.Provider value={{ user, login, logout }}>
|
<AuthContext.Provider value={{ user, login, logout }}>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
Reference in New Issue
Block a user