把 Token 丟去 /auth/verify 只是「確認他是不是合法使用者」,但接下來還有兩件事要處理:
這一節會用 React 最常見的做法:AuthContext + ProtectedRoute 組合拳
不需要上 Redux、不用引入額外套件,小專案、中型應用都適用。
import { createContext, useContext, useState, useEffect } from "react";
import { useVerifyToken } from "../hooks/useVerifyToken";
const AuthContext = createContext(null);
export const AuthProvider = ({ children }) => {
const { verifyToken } = useVerifyToken();
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
// 初始化時就驗證一次
useEffect(() => {
const checkToken = async () => {
try {
const data = await verifyToken();
setUser(data); // { uid, email ... }
} catch {
setUser(null);
} finally {
setLoading(false);
}
};
checkToken();
}, []);
return (
<AuthContext.Provider value={{ user, loading, setUser }}>
{children}
</AuthContext.Provider>
);
};
export const useAuth = () => useContext(AuthContext);
這樣做的好處是:
✅ App 一載入就會自動驗證 Token
✅ 驗證結果會存起來、不會重複打 API
✅ 之後要登出或重新驗證也方便
import { Navigate } from "react-router-dom";
import { useAuth } from "../contexts/AuthContext";
export default function ProtectedRoute({ children }) {
const { user, loading } = useAuth();
if (loading) return <p>驗證中...</p>;
return user ? children : <Navigate to="/login" replace />;
}
import { Routes, Route } from "react-router-dom";
import ProtectedRoute from "./components/ProtectedRoute";
import Dashboard from "./pages/Dashboard";
import Login from "./pages/Login";
export default function AppRoutes() {
return (
<Routes>
<Route path="/login" element={<Login />} />
<Route
path="/dashboard"
element={
<ProtectedRoute>
<Dashboard />
</ProtectedRoute>
}
/>
</Routes>
);
}
import ReactDOM from "react-dom/client";
import AppRoutes from "./App";
import { AuthProvider } from "./contexts/AuthContext";
ReactDOM.createRoot(document.getElementById("root")).render(
<AuthProvider>
<AppRoutes />
</AuthProvider>
);