NextJS13中Auth Context下已登录访问受保护页面仍跳转首页问题
已登录状态下访问受保护Profile页面先显示内容再跳转首页的问题排查与修复
问题根源分析
- AuthContext初始状态错误:
statusAuth初始值设为'unauthenticated',导致页面初始渲染时,Profile组件直接跳过loading分支,先渲染用户信息;同时useEffect检测到初始状态满足跳转条件,触发首页跳转。后续checkIsLoggedin请求完成后状态更新为'authenticated',但跳转已发起,因此出现先显示内容再跳转的异常。 - Token存储/解析不一致:存储token时使用
JSON.stringify,但取出时未解析,导致token包含多余引号,getMe请求的Authorization头无效,服务器返回401,间接触发跳转逻辑。
修复方案
1. 修正AuthContext初始状态
将statusAuth初始值改为'loading',确保认证状态未确定前显示loading,避免错误渲染和跳转:
const [user, setUser] = useState<IUser | null>(null) // 初始状态设为loading,而非unauthenticated const [statusAuth, setStatusAuth] = useState('loading') const checkIsLoggedin = async () => { try { const data = await AxiosGlobal.get('/auth/getMe') if (data.status === 200) { setUser(data.data.user) setStatusAuth('authenticated') } else { setUser(null) setStatusAuth('unauthenticated') } } catch (error) { setUser(null) setStatusAuth('unauthenticated') } } useEffect(() => { checkIsLoggedin() }, []) return ( <AuthContext.Provider value={{ user, setUser, statusAuth, setStatusAuth, }} > {children} </AuthContext.Provider> )
2. 优化Profile组件跳转逻辑
简化useEffect判断条件,仅基于statusAuth做跳转决策:
'use client' import { useContext, useEffect } from "react" import { AuthContext } from "@/contexts/AuthContext" import { useRouter } from 'next/navigation' const Profile = () => { const router = useRouter() const { user, statusAuth } = useContext(AuthContext) useEffect(() => { // 仅当认证状态为unauthenticated时跳转 if(statusAuth === 'unauthenticated') { router.push('/') } }, [router, statusAuth]) if (statusAuth === 'loading') return <>loading.........</> return ( <div>Profile user is here {user?.email}</div> ) } export default Profile
3. 修复Token存储/解析问题
统一token的存储和解析逻辑,避免Authorization头无效:
// Axios请求拦截器修改token获取逻辑 AxiosGlobal.interceptors.request.use(async (config) => { if(config.url === '/auth/refresh-token' && config.method === 'post') { return config } // 解析localStorage中的token,去除多余引号 const tokenStr = localStorage.getItem('accessToken'); const token = tokenStr ? JSON.parse(tokenStr) : null; if(token) { config.headers.Authorization = `Bearer ${token}` } return config }, (error) => { return Promise.reject(error) }) // 同时修改refresh-token成功后的存储逻辑(若token本身是字符串,无需JSON.stringify) // 替换原来的存储代码 localStorage.setItem('accessToken', data.token)
内容的提问来源于stack exchange,提问作者Minh Huy
相关产品推荐
相关产品推荐

