如何在Next.js应用中使用React Context API实现身份验证?
Next.js 结合后端 Passport 身份验证的前端实现方案
核心需求梳理
- 基于 Next.js 开发 React 应用
- 后端采用 Node.js + Passport.js + passport-local-mongoose + express.session 实现身份验证
- 前端使用 Context API 存储用户登录状态数据
现有 AuthContext 代码优化与适配建议
你当前的 AuthProvider 代码已经具备基础的用户状态校验逻辑,但针对 Next.js 环境需要做一些适配和完善:
1. 环境变量适配 Next.js
Next.js 中前端可访问的环境变量需以 NEXT_PUBLIC_ 开头,需修改环境变量名:
// 原代码 const url = process.env.REACT_APP_SERVER; // 修改为 const url = process.env.NEXT_PUBLIC_SERVER;
2. 完善错误处理逻辑
原代码 catch 块为空,建议添加错误提示,方便调试和用户感知:
.catch((err) => { message.error('用户状态校验失败,请刷新页面重试'); console.error('Auth check error:', err); })
3. 添加登录/登出等核心操作方法
在 AuthProvider 中封装与后端交互的身份操作方法,方便组件直接调用:
// 登录方法 const login = useCallback(async (credentials) => { try { const res = await axios.post(`${url}/v1/users/login`, credentials, { withCredentials: true }); setUser(res.data); message.success('登录成功'); return true; } catch (err) { message.error(err.response?.data?.message || '登录失败'); return false; } }, []); // 登出方法 const logout = useCallback(async () => { try { await axios.post(`${url}/v1/users/logout`, {}, { withCredentials: true }); setUser(null); message.success('已退出登录'); } catch (err) { message.error('登出失败'); console.error('Logout error:', err); } }, []); // 在 Provider 的 value 中暴露这些方法 value={{ user, setUser, login, logout }}
4. Next.js 路由适配
若使用 Next.js App Router,需在根布局 layout.js 中引入 AuthProvider,确保全局状态生效:
// app/layout.js import { AuthProvider } from '@/contexts/AuthContext'; export default function RootLayout({ children }) { return ( <html lang="zh-CN"> <body> <AuthProvider>{children}</AuthProvider> </body> </html> ); }
5. 优化加载状态处理
避免页面切换时重复显示加载动画,可结合 Next.js 的 useRouter 调整 useEffect 依赖项,或在页面级别单独处理加载状态。
完整优化后的 AuthProvider 代码
import { createContext, useCallback, useEffect, useState } from 'react'; import { Spin, message } from 'antd'; import axios from 'axios'; const url = process.env.NEXT_PUBLIC_SERVER; export const AuthContext = createContext(); export const AuthProvider = ({ children }) => { const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); // 初始化校验用户状态 useEffect(() => { setLoading(true); const getUser = async () => { const endPoint = `${url}/v1/users/auth`; await axios({ method: 'GET', url: endPoint, withCredentials: true, }) .then((res) => { const { data } = res; setUser(data); }) .catch((err) => { message.error('用户状态校验失败,请刷新页面重试'); console.error('Auth check error:', err); }) .finally(() => { setLoading(false); }); }; getUser(); }, []); // 登录方法 const login = useCallback(async (credentials) => { try { const res = await axios.post(`${url}/v1/users/login`, credentials, { withCredentials: true }); setUser(res.data); message.success('登录成功'); return true; } catch (err) { message.error(err.response?.data?.message || '登录失败'); return false; } }, []); // 登出方法 const logout = useCallback(async () => { try { await axios.post(`${url}/v1/users/logout`, {}, { withCredentials: true }); setUser(null); message.success('已退出登录'); } catch (err) { message.error('登出失败'); console.error('Logout error:', err); } }, []); return ( <AuthContext.Provider value={{ user, setUser, login, logout }}> {loading ? ( <div className='tmtube-global flexCenter'> <Spin size='large' /> </div> ) : ( children )} </AuthContext.Provider> ); };
后端接口配合注意事项
- 确保后端配置正确的跨域规则,允许前端域名携带 Cookie
express.session配置中需设置正确的cookie.domain和sameSite属性,适配前端域名/v1/users/auth接口需根据 session 返回当前登录用户信息,未登录则返回 401 或 null
内容的提问来源于stack exchange,提问作者Jorakuly Atamuradow
相关产品推荐
相关产品推荐

