如何解决NextJS 14 App Router中Header组件刷新后Logout按钮消失问题
解决页面刷新后登录状态丢失的问题
问题核心是useState存储的用户状态在页面刷新时会重置,需要在组件初始化时从后端验证当前登录状态并恢复用户信息。
步骤1:添加登录状态验证与初始化逻辑
修改AdminAuthContext代码,新增状态验证函数,并通过useEffect在组件挂载时自动触发:
"use client"; import { createContext, useContext, useEffect, useState } from "react"; import { useRouter } from 'next/navigation'; const host = process.env.NEXT_PUBLIC_API_HOST; export const AdminAuthContext = createContext({}); export const AdminAuthProvider = ({ children }) => { const router = useRouter(); const [user, setUser] = useState(null); // 验证当前登录状态,从后端拉取用户信息 const checkAuthStatus = async () => { try { const response = await fetch(`${host}/api/admin/me`, { cache: "no-store", credentials: "include", // 携带Cookie中的JWT Token }); if (response.ok) { const res = await response.json(); setUser(res.username); // 恢复用户状态 } else { setUser(null); // 未登录则清空状态 } } catch (error) { console.error("验证登录状态失败:", error); setUser(null); } }; // 组件挂载时自动检查登录状态 useEffect(() => { checkAuthStatus(); }, []); const doAdminLogin = async (email, password) => { const request = await fetch(`${host}/api/admin/login`, { cache: "no-store", method: "POST", credentials: "include", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ email, password }), }); if (!request.ok) { console.error('Login failed'); throw new Error("Error logging in"); } const res = await request.json(); setUser(res.username); router.push('/private/admin/dashboard'); }; const doAdminLogout = async () => { try { const request = await fetch(`${host}/api/admin/logout`, { cache: "no-store", method: "POST", credentials: "include", }); if (request.ok) { setUser(null); // 登出后清空用户状态 router.push('/'); // 跳转到首页或登录页 } } catch (error) { console.error("登出失败:", error); } }; return ( <AdminAuthContext.Provider value={{ user, doAdminLogin, doAdminLogout }}> {children} </AdminAuthContext.Provider> ); }; export function useAdminAuthContext() { return useContext(AdminAuthContext); }
步骤2:确保AdminAuthProvider全局生效
检查你的GlobalProvider是否已经包裹AdminAuthProvider,如果没有,修改GlobalProvider代码:
// _lib/global-provider.js "use client"; import { AdminAuthProvider } from "./admin-auth-provider"; export function GlobalProvider({ children }) { return ( <AdminAuthProvider> {/* 其他全局提供者(如有) */} {children} </AdminAuthProvider> ); }
步骤3:后端实现状态验证接口
Spring Boot需要新增/api/admin/me接口,用于验证Cookie中的JWT Token并返回当前用户信息:
@RestController @RequestMapping("/api/admin") public class AdminController { @GetMapping("/me") public ResponseEntity<Map<String, String>> getCurrentUser(HttpServletRequest request) { // 从Cookie中提取JWT Token String jwtToken = null; Cookie[] cookies = request.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { if ("JWT_TOKEN".equals(cookie.getName())) { // 替换为你的Cookie名称 jwtToken = cookie.getValue(); break; } } } // 验证Token有效性 if (jwtToken == null || !JwtUtil.isValidToken(jwtToken)) { return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } // 提取用户名并返回 String username = JwtUtil.extractUsername(jwtToken); Map<String, String> response = new HashMap<>(); response.put("username", username); return ResponseEntity.ok(response); } }
关键说明
credentials: "include":确保请求携带Cookie,后端才能验证JWT Token的有效性checkAuthStatus函数:页面刷新后自动触发,从后端拉取最新登录状态,恢复用户信息- 完善登出逻辑:调用后端接口后清空
user状态并跳转,避免状态不一致
内容的提问来源于stack exchange,提问作者Marcos
相关产品推荐
相关产品推荐

