Next.js 13(App Router)中配置受保护路由的技术问题
Next.js App Router 受保护路由配置方案咨询
我正在开发一个全栈应用,前端采用Next.js(App Router),后端使用Express.js搭配Passport.js本地策略结合会话完成身份认证。后端的/login、/logout和/user验证路由已经配置完成,目前的难点集中在Next.js前端的受保护路由(如/profile)配置上。
我已经编写了包含login、logout、fetchUser函数的AuthProvider,并将其挂载到RootLayout中。以下是相关代码:
目录结构
应用目录结构大致如下:
- app/
- auth/
- AuthProvider.tsx
- profile/
- page.tsx
- layout.tsx(即RootLayout)
- globals.css
- auth/
AuthProvider.tsx 代码
"use client"; import { createContext, useContext, useState, useEffect } from "react"; import { useRouter } from "next/navigation"; type User = Record<string, unknown> | null; interface AuthContextType { isAuthenticated: boolean; user: User; login: (username: string, password: string) => Promise<void>; isLoading: boolean; logout: () => Promise<void>; } const AuthContext = createContext<AuthContextType>({ isAuthenticated: false, user: null, login: async () => {}, isLoading: true, logout: async () => {} }); function AuthProvider({ children }: { children: React.ReactNode; }) { const [user, setUser] = useState(null); const [isLoading, setLoading] = useState(true); const router = useRouter(); useEffect(() => { fetchUser(); }, []); const fetchUser = async () => { console.log("user fetched"); const response = await fetch("http://localhost:4000/user", { method: "GET", headers: { "Content-Type": "application/json", }, credentials: "include", }); if (response.status === 200) { const data = await response.json(); setUser(data); } else { setUser(null); } setLoading(false); }; const login = async (username: string, password: string) => { const response = await fetch("http://localhost:4000/login", { method: "POST", headers: { Accept: "application/json", "Content-Type": "application/json", }, body: JSON.stringify({ username, password }), credentials: "include", }); if (response.status === 200) { await fetchUser(); router.push("/profile"); } }; const logout = async () => { console.log("Sessão destruída"); await fetch("http://localhost:4000/logout", { method: "POST", credentials: "include", }); setUser(null); router.push('/'); }; return ( <AuthContext.Provider value={{ isAuthenticated: !!user, user, login, isLoading, logout }}> {children} </AuthContext.Provider> ); } export const useAuth = () => useContext(AuthContext); export { AuthProvider };
RootLayout 代码
import "./globals.css"; import { Inter } from "next/font/google"; import { AuthProvider } from "./auth/AuthProvider"; const inter = Inter({ subsets: ["latin"] }); export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <html lang="pt-BR"> <AuthProvider> <body className={inter.className}>{children}</body> </AuthProvider> </html> ); }
我曾考虑在/profile页面中引入useAuth()钩子,判断用户是否已认证,未认证则重定向到登录页,但这样需要将整个页面转为客户端组件,我认为这并非最佳实践。网上多数方案针对旧版页面结构,和我的代码适配性差,恳请提供合适的解决方案。
内容的提问来源于stack exchange,提问作者Pedro H Jalowitzki
相关产品推荐
相关产品推荐

